Esempio n. 1
0
 /* this function returns a new handle...or -1 if no socket could be allocated */
 internal Int32 CreateSocket(ProtocolType protocolType, Int64 timeoutInMachineTicks, bool reservedSocket = false)
 {
     switch (protocolType)
     {
         case ProtocolType.Tcp:
             {
                 int handle = reservedSocket ? GetReservedHandle(timeoutInMachineTicks) : GetNextHandle(timeoutInMachineTicks);
                 if (handle != -1)
                 {
                     _sockets[handle] = new TcpSocket(_tcpHandler, handle);
                     return handle;
                 }
                 else
                 {
                     // no handle available
                     //throw Utility.NewSocketException(SocketError.TooManyOpenSockets);
                     return -1;
                 }
             }
         case ProtocolType.Udp:
             {
                 int handle = reservedSocket ? GetReservedHandle(timeoutInMachineTicks) : GetNextHandle(timeoutInMachineTicks);
                 if (handle != -1)
                 {
                     _sockets[handle] = new UdpSocket(this, handle);
                     return handle;
                 }
                 else
                 {
                     // no handle available
                     //throw Utility.NewSocketException(SocketError.TooManyOpenSockets);
                     return -1;
                 }
             }
         default:
             throw new NotSupportedException();
     }
 }
        bool RetrieveAckNak(UdpSocket socket, UInt32 transactionID, UInt64 clientHardwareAddress, ref DhcpOffer dhcpOffer, out bool responseIsAck, Int64 timeoutInMachineTicks)
        {
            // set default ack/nak response
            responseIsAck = false;

            UInt32 assignedIPAddress;
            DhcpOption[] options;
            bool success = RetrieveDhcpMessage(socket, new DhcpMessageType[] { DhcpMessageType.DHCPACK, DhcpMessageType.DHCPNAK }, transactionID, clientHardwareAddress, out assignedIPAddress, out options, timeoutInMachineTicks);
            if (success == false)
            {
                return false; /* timeout */
            }

            // analyze return value and update offer values if necessary
            for (int iOption = 0; iOption < options.Length; iOption++)
            {
                switch (options[iOption].Code)
                {
                    case DhcpOptionCode.DhcpMessageType:
                        {
                            if (options[iOption].Value.Length >= 1)
                            {
                                responseIsAck = ((DhcpMessageType)options[iOption].Value[0] == DhcpMessageType.DHCPACK);
                            }
                        }
                        break;
                    case DhcpOptionCode.SubnetMask:
                        {
                            if (options[iOption].Value.Length >= 4)
                            {
                                dhcpOffer.SubnetMask = (
                                    (UInt32)(options[iOption].Value[0] << 24) +
                                    (UInt32)(options[iOption].Value[1] << 16) +
                                    (UInt32)(options[iOption].Value[2] << 8) +
                                    (UInt32)(options[iOption].Value[3])
                                    );
                            }
                        }
                        break;
                    case DhcpOptionCode.Router:
                        {
                            /* NOTE: this option may include multiple router addresses; we select the first entry as our default gateway */
                            if (options[iOption].Value.Length >= 4)
                            {
                                dhcpOffer.GatewayAddress = (
                                    (UInt32)(options[iOption].Value[0] << 24) +
                                    (UInt32)(options[iOption].Value[1] << 16) +
                                    (UInt32)(options[iOption].Value[2] << 8) +
                                    (UInt32)(options[iOption].Value[3])
                                    );
                            }
                        }
                        break;
                    case DhcpOptionCode.DomainNameServer:
                        {
                            /* NOTE: this option may include multiple DNS servers; we will only select up to the first two servers as our default DNS servers */
                            System.Collections.ArrayList dnsServerArrayList = new System.Collections.ArrayList();
                            for (int iDnsServer = 0; iDnsServer < options[iOption].Value.Length; iDnsServer += 4)
                            {
                                if (options[iOption].Value.Length >= iDnsServer + 4)
                                {
                                    UInt32 dnsServerAddress = (
                                        (UInt32)(options[iOption].Value[iDnsServer + 0] << 24) +
                                        (UInt32)(options[iOption].Value[iDnsServer + 1] << 16) +
                                        (UInt32)(options[iOption].Value[iDnsServer + 2] << 8) +
                                        (UInt32)(options[iOption].Value[iDnsServer + 3])
                                        );
                                    dnsServerArrayList.Add(dnsServerAddress);
                                }
                            }
                            dhcpOffer.DnsAddresses = (UInt32[])dnsServerArrayList.ToArray(typeof(UInt32));
                        }
                        break;
                    case DhcpOptionCode.IPAddressLeaseTime:
                        {
                            if (options[iOption].Value.Length >= 4)
                            {
                                dhcpOffer.LeaseExpirationTimeInSeconds = (
                                    (UInt32)(options[iOption].Value[0] << 24) +
                                    (UInt32)(options[iOption].Value[1] << 16) +
                                    (UInt32)(options[iOption].Value[2] << 8) +
                                    (UInt32)(options[iOption].Value[3])
                                    );
                            }
                        }
                        break;
                    case DhcpOptionCode.ServerIdentifier:
                        {
                            if (options[iOption].Value.Length >= 4)
                            {
                                dhcpOffer.ServerIdentifier = (
                                    (UInt32)(options[iOption].Value[0] << 24) +
                                    (UInt32)(options[iOption].Value[1] << 16) +
                                    (UInt32)(options[iOption].Value[2] << 8) +
                                    (UInt32)(options[iOption].Value[3])
                                    );
                            }
                        }
                        break;
                    case DhcpOptionCode.RenewalTimeValue:
                        {
                            if (options[iOption].Value.Length >= 4)
                            {
                                dhcpOffer.LeaseRenewalTimeInSeconds = (
                                    (UInt32)(options[iOption].Value[0] << 24) +
                                    (UInt32)(options[iOption].Value[1] << 16) +
                                    (UInt32)(options[iOption].Value[2] << 8) +
                                    (UInt32)(options[iOption].Value[3])
                                    );
                            }
                        }
                        break;
                    case DhcpOptionCode.RebindingTimeValue:
                        {
                            if (options[iOption].Value.Length >= 4)
                            {
                                dhcpOffer.LeaseRebindingTimeInSeconds = (
                                    (UInt32)(options[iOption].Value[0] << 24) +
                                    (UInt32)(options[iOption].Value[1] << 16) +
                                    (UInt32)(options[iOption].Value[2] << 8) +
                                    (UInt32)(options[iOption].Value[3])
                                    );
                            }
                        }
                        break;
                    case DhcpOptionCode.ClientIdentifier:
                        /* NOTE: we ignore this since our hardware address matches, although if we ever need to verify it then we can do so here */
                        break;
                }
            }

            return true; /* success */
        }
        bool RetrieveDhcpMessage(UdpSocket socket, DhcpMessageType[] messageTypes, UInt32 transactionID, UInt64 clientHardwareAddress, out UInt32 assignedIPAddress, out DhcpOption[] options, Int64 timeoutInMachineTicks)
        {
            byte[] dhcpFrameBuffer = new byte[DHCP_FRAME_BUFFER_LENGTH];
            while (timeoutInMachineTicks > Microsoft.SPOT.Hardware.Utility.GetMachineTime().Ticks)
            {
                Int32 bytesReceived = socket.Receive(dhcpFrameBuffer, 0, dhcpFrameBuffer.Length, 0, timeoutInMachineTicks);

                if (bytesReceived == 0) // timeout
                    break;

                /* parse our DHCP frame */
                // validate the operation
                if ((BootpOperation)dhcpFrameBuffer[0] != BootpOperation.BOOTREPLY)
                    continue; /* filter out this BOOTP/DHCP frame */
                /* verify magic cookie {99, 130, 83, 99} is the first 4-byte entry, as per RFC 1497 */
                if ((dhcpFrameBuffer[236] != 99) ||
                    (dhcpFrameBuffer[237] != 130) ||
                    (dhcpFrameBuffer[238] != 83) ||
                    (dhcpFrameBuffer[239] != 99))
                    continue; /* filter out this BOOTP non-DHCP frame */
                // verify that the transaction ID matches
                UInt32 verifyTransactionID = (
                    (UInt32)(dhcpFrameBuffer[4] << 24) +
                    (UInt32)(dhcpFrameBuffer[5] << 16) +
                    (UInt32)(dhcpFrameBuffer[6] << 8) +
                    (UInt32)(dhcpFrameBuffer[7])
                    );
                if (transactionID != verifyTransactionID)
                    continue; /* filter out this DHCP frame */
                // verify the the physical hardware type matches
                if (dhcpFrameBuffer[1] != (byte)HARDWARE_TYPE_ETHERNET)
                    continue; /* filter out this DHCP frame */
                if (dhcpFrameBuffer[2] != (byte)HARDWARE_ADDRESS_SIZE)
                    continue; /* filter out this DHCP frame */
                // verify that the physical address matches
                UInt64 verifyClientHardwareAddress = (
                    ((UInt64)(dhcpFrameBuffer[28]) << 40) +
                    ((UInt64)(dhcpFrameBuffer[29]) << 32) +
                    ((UInt64)(dhcpFrameBuffer[30]) << 24) +
                    ((UInt64)(dhcpFrameBuffer[31]) << 16) +
                    ((UInt64)(dhcpFrameBuffer[32]) << 8) +
                    (UInt64)(dhcpFrameBuffer[33])
                    );
                if (clientHardwareAddress != verifyClientHardwareAddress)
                    continue; /* filter out this DHCP frame */

                // retrieve allocated ip address
                /* yiaddr (ip address, populated by server */
                assignedIPAddress = (
                    (UInt32)(dhcpFrameBuffer[16] << 24) +
                    (UInt32)(dhcpFrameBuffer[17] << 16) +
                    (UInt32)(dhcpFrameBuffer[18] << 8) +
                    (UInt32)(dhcpFrameBuffer[19])
                    );
                // retrieve options
                System.Collections.ArrayList optionsArrayList = new System.Collections.ArrayList();
                bool optionOverloadReceived = false;
                DhcpOptionsBlockRange[] optionsBlocks = new DhcpOptionsBlockRange[]
                {
                    new DhcpOptionsBlockRange(240, DHCP_FRAME_BUFFER_LENGTH - 240 - 1),
                };
                int optionsBlocksIndex = 0;

                DhcpMessageType verifyMessageType = 0;
                while (optionsBlocksIndex < optionsBlocks.Length)
                {
                    Int32 index = optionsBlocks[optionsBlocksIndex].BeginOffset;
                    bool endOpcodeReceived = false;
                    while (!endOpcodeReceived && index <= optionsBlocks[optionsBlocksIndex].EndOffset)
                    {
                        DhcpOptionCode optionCode = (DhcpOptionCode)dhcpFrameBuffer[index];
                        switch ((DhcpOptionCode)optionCode)
                        {
                            case DhcpOptionCode.Pad:
                                {
                                    index++;
                                }
                                break;
                            case DhcpOptionCode.End:
                                {
                                    index++;
                                    endOpcodeReceived = true;
                                }
                                break;
                            case DhcpOptionCode.OptionOverload:
                                {
                                    if (optionsBlocksIndex == 0)
                                    {
                                        index++;
                                        if (dhcpFrameBuffer[index] != 1)
                                            break;
                                        index++;
                                        byte value = dhcpFrameBuffer[index];
                                        index++;
                                        int numBlocks = 1 + (((value & 0x01) == 0x01) ? 1 : 0) + (((value & 0x02) == 0x02) ? 1 : 0);
                                        optionsBlocks = new DhcpOptionsBlockRange[numBlocks];
                                        int iOptionBlock = 0;
                                        optionsBlocks[iOptionBlock++] = new DhcpOptionsBlockRange(240, DHCP_FRAME_BUFFER_LENGTH - 240 - 1);
                                        if ((value & 0x01) == 0x01)
                                        {
                                            /* use file field for extended options */
                                            optionsBlocks[iOptionBlock++] = new DhcpOptionsBlockRange(108, 235);
                                        }
                                        if ((value & 0x02) == 0x02)
                                        {
                                            /* use sname field for extended options */
                                            optionsBlocks[iOptionBlock++] = new DhcpOptionsBlockRange(44, 107);
                                        }
                                    }
                                }
                                break;
                            default:
                                {
                                    index++;
                                    byte[] value = new byte[Math.Min(dhcpFrameBuffer[index], DHCP_FRAME_BUFFER_LENGTH - index)];
                                    index++;
                                    Array.Copy(dhcpFrameBuffer, index, value, 0, value.Length);
                                    index += value.Length;

                                    // if the option already exists, append to it
                                    bool foundOption = false;
                                    for (int iExistingOption = 0; iExistingOption < optionsArrayList.Count; iExistingOption++)
                                    {
                                        if (((DhcpOption)optionsArrayList[iExistingOption]).Code == optionCode)
                                        {
                                            byte[] newValue = new byte[((DhcpOption)optionsArrayList[iExistingOption]).Value.Length + value.Length];
                                            Array.Copy(((DhcpOption)optionsArrayList[iExistingOption]).Value, 0, newValue, 0, ((DhcpOption)optionsArrayList[iExistingOption]).Value.Length);
                                            Array.Copy(value, 0, newValue, ((DhcpOption)optionsArrayList[iExistingOption]).Value.Length, value.Length);
                                            optionsArrayList.RemoveAt(iExistingOption);
                                            optionsArrayList.Add(new DhcpOption(optionCode, newValue));

                                            foundOption = true;
                                            break;
                                        }
                                    }
                                    if (!foundOption)
                                    {
                                        optionsArrayList.Add(new DhcpOption(optionCode, value));
                                    }

                                    if (optionCode == DhcpOptionCode.DhcpMessageType)
                                    {
                                        verifyMessageType = (DhcpMessageType)value[0];
                                    }
                                }
                                break;
                        }
                    }

                    optionsBlocksIndex++;
                }
                options = (DhcpOption[])optionsArrayList.ToArray(typeof(DhcpOption));

                // verify that the DHCP message type matches
                bool messageTypeMatches = false;
                for (int iMessageType = 0; iMessageType < messageTypes.Length; iMessageType++)
                {
                    if (messageTypes[iMessageType] == verifyMessageType)
                    {
                        messageTypeMatches = true;
                        break;
                    }
                }

                if (messageTypeMatches)
                    return true; /* message matches the messageTypes filter, with a valid frame; return all data to the caller  */
            }

            // if we did not receive a message before timeout, return false.
            // set default return values
            assignedIPAddress = 0;
            options = null;
            return false;
        }
        void SendDhcpMessage(UdpSocket socket, DhcpMessageType messageType, UInt32 dhcpServerIPAddress, UInt32 transactionID, UInt16 secondsElapsed, UInt32 clientIPAddress, UInt64 clientHardwareAddress, DhcpOption[] options, Int64 timeoutInMachineTicks)
        {
            if (_isDisposed) return;

            byte[] dhcpFrameBuffer = new byte[DHCP_FRAME_BUFFER_LENGTH];

            // configure DHCP frame
            /* op (bootp operation) */
            dhcpFrameBuffer[0] = (byte)BootpOperation.BOOTREQUEST;
            /* htype (hardware type) */
            dhcpFrameBuffer[1] = (byte)HARDWARE_TYPE_ETHERNET;
            /* hlen (hardware address length) */
            dhcpFrameBuffer[2] = (byte)HARDWARE_ADDRESS_SIZE;
            /* hops (bootp relay hops; we should always set this to zero) */
            dhcpFrameBuffer[3] = 0;
            /* xid (transaction id; this should be a randomly-generated number) */
            dhcpFrameBuffer[4] = (byte)((transactionID >> 24) & 0xFF);
            dhcpFrameBuffer[5] = (byte)((transactionID >> 16) & 0xFF);
            dhcpFrameBuffer[6] = (byte)((transactionID >> 8) & 0xFF);
            dhcpFrameBuffer[7] = (byte)(transactionID & 0xFF);
            /* secs (seconds elasped since start of DHCP config acquisition process) */
            dhcpFrameBuffer[8] = (byte)((secondsElapsed >> 8) & 0xFF);
            dhcpFrameBuffer[9] = (byte)(secondsElapsed & 0xFF);
            /* flags (most significant bit is broadcast flags; all others are zeroes) */
            /* some DHCP servers do not process the broadcast flag properly, so we allow all broadcast and unicast packets with our hardwareAddress to pass through to the UDP layer instead */
            /* see https://support.microsoft.com/en-us/kb/928233 for more details */
            dhcpFrameBuffer[10] = 0x00; // 0x80; 
            dhcpFrameBuffer[11] = 0x00;
            /* ciaddr (client ip address; only filled in if client can respond to ARP requests and is in BOUND, RENEW or REBINDING state) */
            dhcpFrameBuffer[12] = (byte)((clientIPAddress >> 24) & 0xFF);
            dhcpFrameBuffer[13] = (byte)((clientIPAddress >> 16) & 0xFF);
            dhcpFrameBuffer[14] = (byte)((clientIPAddress >> 8) & 0xFF);
            dhcpFrameBuffer[15] = (byte)(clientIPAddress & 0xFF);
            /* yiaddr (ip address, populated by server; this should always be zero in client requests */
            dhcpFrameBuffer[16] = 0;
            dhcpFrameBuffer[17] = 0;
            dhcpFrameBuffer[18] = 0;
            dhcpFrameBuffer[19] = 0;
            /* siaddr (ip address of next address to use in bootp boot process, populated by server; this should always be zero in client requests */
            dhcpFrameBuffer[20] = 0;
            dhcpFrameBuffer[21] = 0;
            dhcpFrameBuffer[22] = 0;
            dhcpFrameBuffer[23] = 0;
            /* giaddr (ip address of relay agent, populated by relay agents; this should always be zero in client requests */
            dhcpFrameBuffer[24] = 0;
            dhcpFrameBuffer[25] = 0;
            dhcpFrameBuffer[26] = 0;
            dhcpFrameBuffer[27] = 0;
            /* chaddr (client hardware address; we fill in the first 6 bytes with our MAC address) */
            dhcpFrameBuffer[28] = (byte)((clientHardwareAddress >> 40) & 0xFF);
            dhcpFrameBuffer[29] = (byte)((clientHardwareAddress >> 32) & 0xFF);
            dhcpFrameBuffer[30] = (byte)((clientHardwareAddress >> 24) & 0xFF);
            dhcpFrameBuffer[31] = (byte)((clientHardwareAddress >> 16) & 0xFF);
            dhcpFrameBuffer[32] = (byte)((clientHardwareAddress >> 8) & 0xFF);
            dhcpFrameBuffer[33] = (byte)(clientHardwareAddress & 0xFF);
            Array.Clear(dhcpFrameBuffer, 34, 10);
            /* sname (null-terminated server hostname, populated by server; always set to zero in client requests */
            Array.Clear(dhcpFrameBuffer, 44, 64);
            /* file (null-terminated boot file name, populaetd by server; always set to zero in client requests */
            Array.Clear(dhcpFrameBuffer, 108, 128);
            /* options; NOTE: we do support overflowing options into the sname and file fields in this implementation of DHCP. */
            /* magic cookie {99, 130, 83, 99} is the first 4-byte entry, as per RFC 1497 */
            dhcpFrameBuffer[236] = 99;
            dhcpFrameBuffer[237] = 130;
            dhcpFrameBuffer[238] = 83;
            dhcpFrameBuffer[239] = 99;
            /* now we fill in the options (starting with the DhcpMessageType, then all of the passed-in options, and then the END option */
            dhcpFrameBuffer[240] = (byte)DhcpOptionCode.DhcpMessageType;
            dhcpFrameBuffer[241] = 1; /* Length */
            dhcpFrameBuffer[242] = (byte)messageType;
            int currentOptionPos = 243;
            if (options != null)
            {
                for (int iOption = 0; iOption < options.Length; iOption++)
                {
                    /* do not include missing/empty options (or pad) */
                    if (options[iOption].Code != 0)
                    {
                        // if this option will not fit in the options section, stop processing options.
                        if (currentOptionPos + options.Length + 2 /* size of code + length bytes */ + 1 /* size of END option */ > DHCP_FRAME_BUFFER_LENGTH)
                            break;

                        dhcpFrameBuffer[currentOptionPos++] = (byte)options[iOption].Code;
                        dhcpFrameBuffer[currentOptionPos++] = (byte)options[iOption].Value.Length;
                        Array.Copy(options[iOption].Value, 0, dhcpFrameBuffer, currentOptionPos, options[iOption].Value.Length);
                        currentOptionPos += options[iOption].Value.Length;
                    }
                }
            }
            /* finish with "END" option */
            dhcpFrameBuffer[currentOptionPos++] = (byte)DhcpOptionCode.End;
            Array.Clear(dhcpFrameBuffer, currentOptionPos, DHCP_FRAME_BUFFER_LENGTH - currentOptionPos);

            // expand frame to word boundary, just in case DHCP servers have troubles processing non-aligned frames.
            Int32 lengthOfFrame = Math.Min(currentOptionPos + (currentOptionPos % 4 != 0 ? (4 - (currentOptionPos % 4)) : 0), DHCP_FRAME_BUFFER_LENGTH);

            socket.SendTo(dhcpFrameBuffer, 0, lengthOfFrame, 0, timeoutInMachineTicks, dhcpServerIPAddress, DHCP_SERVER_PORT);
        }
Esempio n. 5
0
        bool RetrieveDnsResponse(UdpSocket socket, UInt16 transactionID, out DnsResponse dnsResponse, Int64 timeoutInMachineTicks)
        {
            byte[] dnsFrameBuffer = new byte[DNS_FRAME_BUFFER_LENGTH];
            while (timeoutInMachineTicks > Microsoft.SPOT.Hardware.Utility.GetMachineTime().Ticks)
            {
                Int32 bytesReceived = socket.Receive(dnsFrameBuffer, 0, dnsFrameBuffer.Length, 0, timeoutInMachineTicks);

                if (bytesReceived == 0) // timeout
                {
                    break;
                }

                /* parse our DNS response */
                Int32 bufferIndex = 0;
                // verify that the transaction ID matches
                UInt16 verifyTransactionID = (UInt16)(
                    (UInt16)(dnsFrameBuffer[bufferIndex++] << 8) +
                    (UInt16)(dnsFrameBuffer[bufferIndex++])
                    );
                if (transactionID != verifyTransactionID)
                    continue; /* filter out this DHCP frame */
                // Flags
                UInt16 flags = (UInt16)(
                    (UInt16)(dnsFrameBuffer[bufferIndex++] << 8) +
                    (UInt16)(dnsFrameBuffer[bufferIndex++])
                    );
                DnsResponseCode responseCode = (DnsResponseCode)(flags & 0x0F);
                // Query Count
                UInt16 queryCount = (UInt16)(
                    (UInt16)(dnsFrameBuffer[bufferIndex++] << 8) +
                    (UInt16)(dnsFrameBuffer[bufferIndex++])
                    );
                // Answer Record Count
                UInt16 answerRecordCount = (UInt16)(
                    (UInt16)(dnsFrameBuffer[bufferIndex++] << 8) +
                    (UInt16)(dnsFrameBuffer[bufferIndex++])
                    );
                // Authority Record Count
                UInt16 authorityRecordCount = (UInt16)(
                    (UInt16)(dnsFrameBuffer[bufferIndex++] << 8) +
                    (UInt16)(dnsFrameBuffer[bufferIndex++])
                    );
                // Additional Information Record Count
                UInt16 additionalInformationRecordCount = (UInt16)(
                    (UInt16)(dnsFrameBuffer[bufferIndex++] << 8) +
                    (UInt16)(dnsFrameBuffer[bufferIndex++])
                    );

                /* parse our query records */
                string queryName = "";
                DnsRecordType queryType = (DnsRecordType)0;
                for (int iRecord = 0; iRecord < queryCount; iRecord++)
                {
                    // Query Name
                    bufferIndex += ParseDnsName(dnsFrameBuffer, bufferIndex, out queryName);
                    queryType = (DnsRecordType)(
                        (UInt16)(dnsFrameBuffer[bufferIndex++] << 8) +
                        (UInt16)(dnsFrameBuffer[bufferIndex++])
                        );
                    UInt16 queryClass = (UInt16)(
                        (UInt16)(dnsFrameBuffer[bufferIndex++] << 8) +
                        (UInt16)(dnsFrameBuffer[bufferIndex++])
                        );
                    if (queryClass != DNS_RECORD_CLASS_INTERNET)
                        continue; /* filter out the current query */
                }

                /* parse our answer records */
                DnsResourceRecord[] answerRecords = new DnsResourceRecord[answerRecordCount];
                for (int iRecord = 0; iRecord < answerRecordCount; iRecord++)
                {
                    // store answer record
                    bufferIndex += ParseResourceRecord(dnsFrameBuffer, bufferIndex, out answerRecords[iRecord]);
                }

                /* parse our authority records */
                DnsResourceRecord[] authorityRecords = new DnsResourceRecord[authorityRecordCount];
                for (int iRecord = 0; iRecord < authorityRecordCount; iRecord++)
                {
                    // store authority record
                    bufferIndex += ParseResourceRecord(dnsFrameBuffer, bufferIndex, out authorityRecords[iRecord]);
                }

                /* parse our authority records */
                DnsResourceRecord[] additionalInformationRecords = new DnsResourceRecord[additionalInformationRecordCount];
                for (int iRecord = 0; iRecord < additionalInformationRecordCount; iRecord++)
                {
                    // store authority record
                    bufferIndex += ParseResourceRecord(dnsFrameBuffer, bufferIndex, out additionalInformationRecords[iRecord]);
                }

                dnsResponse = new DnsResponse(responseCode, queryType, queryName, answerRecords, authorityRecords, additionalInformationRecords);
                return true;
            }

            // if we did not receive a message before timeout, return false.
            dnsResponse = null;
            return false;
        }