/// <summary> /// Shorthand form to make MX querying easier, essentially wraps up the retreival /// of the MX records, and sorts them by preference /// </summary> /// <param name="domain">domain name to retreive MX RRs for</param> /// <param name="port">the port number used by the domain name server.</param> /// <param name="ipAddress">the ip address of the domain name server.</param> /// <param name="protocolType">the protocol type used by the domain name server.</param> /// <param name="useIPv4EndPoint">use only an IPv4 connection and disregard all other address families (IPv6).</param> /// <returns>An array of MXRecords</returns> internal MXRecord[] MXLookup(string domain, int port, string ipAddress, Nequeo.Net.Dns.ProtocolType protocolType, bool useIPv4EndPoint) { // check the inputs if (domain == null) { throw new ArgumentNullException("domain"); } if (port < 1) { throw new IndexOutOfRangeException("port"); } // create a request for this Request request = new Request(); // add one question - the MX IN lookup for the supplied domain request.AddQuestion(new Question(domain, Nequeo.Net.Dns.DnsType.MX, Nequeo.Net.Dns.DnsClass.IN)); // fire it off Response response = Lookup(request, domain, port, ipAddress, protocolType, useIPv4EndPoint); // if we didn't get a response, then return null if (response == null) { return(null); } // create a growable array of MX records ArrayList resourceRecords = new ArrayList(); // add each of the answers to the array foreach (Answer answer in response.Answers) { // if the answer is an MX record if (answer.Record.GetType() == typeof(MXRecord)) { // add it to our array resourceRecords.Add(answer.Record); } } // create array of MX records MXRecord[] mxRecords = new MXRecord[resourceRecords.Count]; // copy from the array list resourceRecords.CopyTo(mxRecords); // sort into lowest preference order Array.Sort(mxRecords); // and return return(mxRecords); }
/// <summary> /// The principal look up function, which sends a request message to the given /// DNS server and collects a response. This implementation re-sends the message /// via UDP up to two times in the event of no response/packet loss /// </summary> /// <param name="request">The logical request to send to the server</param> /// <param name="domain">domain name to retreive MX RRs for</param> /// <param name="port">the port number used by the domain name server.</param> /// <param name="ipAddress">the ip address of the domain name server.</param> /// <param name="protocolType">the protocol type used by the domain name server.</param> /// <param name="useIPv4EndPoint">use only an IPv4 connection and disregard all other address families (IPv6).</param> /// <returns>The logical response from the DNS server or null if no response</returns> internal Response Lookup(Request request, string domain, int port, string ipAddress, Nequeo.Net.Dns.ProtocolType protocolType, bool useIPv4EndPoint) { // check the inputs if (request == null) { throw new ArgumentNullException("request"); } if (port < 1) { throw new IndexOutOfRangeException("port"); } // get the message byte[] requestMessage = request.GetMessage(); // send the request and get the response byte[] responseMessage = Transfer(domain, port, ipAddress, protocolType, requestMessage, useIPv4EndPoint); string ff = Encoding.ASCII.GetString(responseMessage); // and populate a response object from that and return it return(new Response(responseMessage)); }
/// <summary> /// Get the client connection socket. /// </summary> /// <param name="ipAddress">the ip address of the domain name server.</param> /// <param name="port">the port number used by the domain name server.</param> /// <param name="protocolType">the protocol type used by the domain name server.</param> /// <param name="useIPv4EndPoint">use only an IPv4 connection and disregard all other address families (IPv6).</param> /// <returns>The client connection socket.</returns> private Socket GetSocket(string ipAddress, int port, Nequeo.Net.Dns.ProtocolType protocolType, bool useIPv4EndPoint) { Socket socket = null; try { IPHostEntry hostEntry = null; // Get host related information. hostEntry = System.Net.Dns.GetHostEntry(ipAddress); // Loop through the AddressList to obtain the supported // AddressFamily. This is to avoid an exception that // occurs when the host IP Address is not compatible // with the address family // (typical in the IPv6 case). foreach (IPAddress address in hostEntry.AddressList) { // If the connection used should only be IPv4. if (useIPv4EndPoint && address.AddressFamily == AddressFamily.InterNetworkV6) { continue; } // Get the current server endpoint for // the current address. IPEndPoint endPoint = new IPEndPoint(address, port); Socket tempSocket = null; // Get the current socket type. switch (protocolType) { case Nequeo.Net.Dns.ProtocolType.Tcp: // Create a new client socket for the // current endpoint. tempSocket = new Socket(endPoint.AddressFamily, SocketType.Dgram, System.Net.Sockets.ProtocolType.Tcp); break; case Nequeo.Net.Dns.ProtocolType.Udp: // Create a new client socket for the // current endpoint. tempSocket = new Socket(endPoint.AddressFamily, SocketType.Dgram, System.Net.Sockets.ProtocolType.Udp); break; } // Connect to the server with the // current end point. try { tempSocket.Connect(endPoint); } catch { } // If this connection succeeded then // asiign the client socket and // break put of the loop. if (tempSocket.Connected) { // A client connection has been found. // Break out of the loop. socket = tempSocket; break; } else { continue; } } // Return the client socket. return(socket); } catch (Exception e) { throw new Exception(e.Message); } }
/// <summary> /// Gets the bytes of data from the domain name server socket connection. /// </summary> /// <param name="domain">domain name to retreive MX RRs for</param> /// <param name="port">the port number used by the domain name server.</param> /// <param name="ipAddress">the ip address of the domain name server.</param> /// <param name="protocolType">the protocol type used by the domain name server.</param> /// <param name="useIPv4EndPoint">use only an IPv4 connection and disregard all other address families (IPv6).</param> /// <param name="requestMessage"></param> /// <returns>The bytes received from the domain name server.</returns> private byte[] Transfer(string domain, int port, string ipAddress, Nequeo.Net.Dns.ProtocolType protocolType, byte[] requestMessage, bool useIPv4EndPoint) { // UDP can fail - if it does try again keeping track of how many attempts we've made int attempts = 0; // try repeatedly in case of failure while (attempts <= _udpRetryAttempts) { // firstly, uniquely mark this request with an id unchecked { // substitute in an id unique to this lookup, the request has no idea about this requestMessage[0] = (byte)(_uniqueId >> 8); requestMessage[1] = (byte)_uniqueId; } // we'll be send and receiving a UDP packet Socket socket = GetSocket(ipAddress, port, protocolType, useIPv4EndPoint); // we will wait at most 10 second for a dns reply socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReceiveTimeout, 10000); // send it off to the server socket.Send(requestMessage, requestMessage.Length, SocketFlags.None); // RFC1035 states that the maximum size of a UDP datagram is 512 octets (bytes) byte[] responseMessage = new byte[512]; try { // wait for a response upto 10 second socket.Receive(responseMessage); // make sure the message returned is ours if (responseMessage[0] == requestMessage[0] && responseMessage[1] == requestMessage[1]) { // its a valid response - return it, this is our successful exit point return(responseMessage); } } catch (SocketException) { // failure - we better try again, but remember how many attempts attempts++; } finally { // increase the unique id _uniqueId++; // close the socket socket.Close(); } } // the operation has failed, this is our unsuccessful exit point throw new Exception("A connection could not be establised. " + "The server may have actively refused the request."); }