private static Int16 toSetAppropriateEndianess(Int16 value) { return(Endianess.MachineArchIsLittleEndian ? Endianess.toBigEndian(value) : value); }
public bool AskDNS(string domain, string email) { var transactionID = (Int16)(new Random().Next(maxValue: Int16.MaxValue)); var header = new DNSHeader { transactionID = transactionID, flags = 0x0100, // Just a standard query questionResourceCount = 1, // We have one question answerResourceCount = 0, authorityResourceCount = 0, additionalResourceCount = 0 }; var question = new DNSQuestion(domain, DNSQuestion.Types.MailExchangeRecord); // We want to know about mail server var sizeDNSQuery = header.SizeOf() + question.SizeOf(); var arrDNSQuery = new byte[sizeDNSQuery]; IntPtr ptrHeader = Marshal.AllocHGlobal(header.SizeOf()); Marshal.StructureToPtr(header, ptrHeader, true); Marshal.Copy(ptrHeader, arrDNSQuery, 0, header.SizeOf()); Marshal.FreeHGlobal(ptrHeader); // Copy char data, no need to worry about endianess for char question.name.CopyTo(arrDNSQuery, header.SizeOf()); var arrQuestionType = BitConverter.GetBytes(Endianess.toBigEndian(question.type)); var arrQuestionClassType = BitConverter.GetBytes(Endianess.toBigEndian(question.classType)); arrQuestionType.CopyTo(arrDNSQuery, header.SizeOf() + question.name.Length * sizeof(byte)); arrQuestionClassType.CopyTo(arrDNSQuery, header.SizeOf() + question.name.Length * sizeof(byte) + arrQuestionType.Length); // Send datagram _dNSClient.Send(arrDNSQuery, arrDNSQuery.Length * sizeof(byte)); // Get response do { var result = _dNSClient.ReceiveAsync().Result; // Make sure it is from correct domain if (result.RemoteEndPoint.Address.Equals(_dNSServer)) { // Make sure packet has valid size header if (result.Buffer.Length > header.SizeOf()) { // Convert to DNSHeader ptrHeader = Marshal.AllocHGlobal(header.SizeOf()); Marshal.Copy(result.Buffer, 0, ptrHeader, header.SizeOf()); header = (DNSHeader)Marshal.PtrToStructure(ptrHeader, header.GetType()); Marshal.FreeHGlobal(ptrHeader); // Check that this is the correct transaction packet response if (header.transactionID == transactionID) { // Check that flags has no error and there is atleast one answer if (((header.flags & 0xf) != 0) || header.answerResourceCount == 0) { return(false); } // List of mail servers and their preferences List <Tuple <int, string> > listMailServerAndPrefs = new List <Tuple <int, string> >(); // Determine the start index of Answers structure int indexStartOfAnswer = arrDNSQuery.Length; for (int i = 0; i < header.answerResourceCount; ++i) { if ((result.Buffer[indexStartOfAnswer] & 0xC0) == 0) { throw new NotImplementedException("DNS answer name must be an offset"); } // Convert from byte stream to answer structure IntPtr ptrAnswer = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(DNSResource))); Marshal.Copy(result.Buffer, indexStartOfAnswer, ptrAnswer, Marshal.SizeOf(typeof(DNSResource))); var answer = (DNSResource)Marshal.PtrToStructure(ptrAnswer, typeof(DNSResource)); Marshal.FreeHGlobal(ptrAnswer); // Increment index ahead indexStartOfAnswer += answer.SizeOf(); if (indexStartOfAnswer > result.Buffer.Length) { break; } // Read preference no, smaller number is more preferred server if (answer.dataLength < 2) { continue; } Int16 preferenceMailExchangeServer = BitConverter.ToInt16(result.Buffer, indexStartOfAnswer); if (Endianess.MachineArchIsLittleEndian) { preferenceMailExchangeServer = Endianess.toLittleEndian(preferenceMailExchangeServer); } indexStartOfAnswer += Marshal.SizeOf(preferenceMailExchangeServer); // Read server name int sizeServerName = answer.dataLength - Marshal.SizeOf(preferenceMailExchangeServer); if (sizeServerName < 2) { continue; } if (indexStartOfAnswer + sizeServerName > result.Buffer.Length) { break; } string serverName = string.Empty; int j = indexStartOfAnswer; while (j < indexStartOfAnswer + sizeServerName - 1) { if ((result.Buffer[j] & 0xC0) != 0) { // It's an offset var offset = BitConverter.ToInt16(result.Buffer, j); if (Endianess.MachineArchIsLittleEndian) { offset = Endianess.toLittleEndian(offset); } offset &= 0x3F; // Remove two most significant bits j += Marshal.SizeOf(offset); // Transverse position from offset until null do { serverName += Encoding.ASCII.GetString(result.Buffer, offset + 1, result.Buffer[offset]) + '.'; offset += (Int16)(result.Buffer[offset] + 1); } while (result.Buffer[offset] != 0); } else { // It's just size serverName += System.Text.Encoding.ASCII.GetString(result.Buffer, j + 1, result.Buffer[j]) + '.'; j += result.Buffer[j] + 1; } } indexStartOfAnswer += answer.dataLength - Marshal.SizeOf(preferenceMailExchangeServer); if (string.IsNullOrEmpty(serverName) && serverName.Length > 2) { continue; } serverName = serverName.Substring(0, serverName.Length - 1); // Remove terminating dot listMailServerAndPrefs.Add(new Tuple <int, string>((int)preferenceMailExchangeServer, serverName)); } // Sort by preference listMailServerAndPrefs = listMailServerAndPrefs.OrderBy(x => x.Item1).ToList(); // Connect with SMTP _sMTPClient = new TcpClient(); _sMTPClient.ConnectAsync(listMailServerAndPrefs.First().Item2, _sMTPPort).Wait(); if (!_sMTPClient.Connected) { throw new WebException("SMTP server refused connection"); } var arrSMTPResponse = new byte[256]; var sizeSMTPResponse = _sMTPClient.Client.Receive(arrSMTPResponse); var connectResponse = Encoding.ASCII.GetString(arrSMTPResponse); if (!connectResponse.StartsWith("220")) { throw new WebException("SMTP server refused to connect"); } _sMTPClient.Client.Send(Encoding.ASCII.GetBytes("HELO " + HelloServer + "\r\n")); sizeSMTPResponse = _sMTPClient.Client.Receive(arrSMTPResponse); var heloResponse = Encoding.ASCII.GetString(arrSMTPResponse); if (!heloResponse.StartsWith("250")) { throw new WebException("SMTP server refused to handshake"); } _sMTPClient.Client.Send(Encoding.ASCII.GetBytes("MAIL FROM:<" + QueryEmail + ">\r\n")); sizeSMTPResponse = _sMTPClient.Client.Receive(arrSMTPResponse); var mailfromResponse = Encoding.ASCII.GetString(arrSMTPResponse); if (!mailfromResponse.StartsWith("250")) { throw new WebException("SMTP server refused to accept mail from"); } _sMTPClient.Client.Send(Encoding.ASCII.GetBytes("RCPT TO:<" + email + ">\r\n")); sizeSMTPResponse = _sMTPClient.Client.Receive(arrSMTPResponse); var rcpttoResponse = Encoding.ASCII.GetString(arrSMTPResponse); _sMTPClient.Client.Send(Encoding.ASCII.GetBytes("QUIT")); // Bye _sMTPClient.Close(); if (!rcpttoResponse.StartsWith("250")) { return(false); } break; } } } } while (true); return(true); }