Hardware fingerprint class in C# - c#

I'm using the following class to generate a unique hardware ID for a basic software licencing system.
The problem is that in some cases the fingerprint produced is different, without any hardware change.
I have not developed a client-side debugging system to isolate the component that causes the problem, so i'd like to ask if and under what conditions the following code could generate different IDs for the same hardware.
I already removed the network adaptor part (caused variations when many adaptors existed) and the hard disk part (problems when a usb drive was attached).
But the remaining components' IDs should remain the same, even after software changes and windows updates, isn't so?
public static class FingerPrint
{
private static string fingerPrint = string.Empty;
//--------------------------------------
public static string Base64Encode(string plainText)
{
var plainTextBytes = System.Text.Encoding.UTF8.GetBytes(plainText);
return System.Convert.ToBase64String(plainTextBytes);
}
//--------------------------------------
public static string Value()
{
string cpu = cpuId();
string bios = biosId();
string bas = baseId();
string video = videoId();
if (string.IsNullOrEmpty(fingerPrint))
{
fingerPrint = GetHash("CPU >> " + cpu + "\nBIOS >> " +
bios + "\nBASE >> " + bas
+ "\nVIDEO >> " + video
+ "\n some_salt");
}
return Base64Encode(fingerPrint);
}
//--------------------------------------
private static string GetHash(string s)
{
MD5 sec = new MD5CryptoServiceProvider();
ASCIIEncoding enc = new ASCIIEncoding();
byte[] bt = enc.GetBytes(s);
return GetHexString(sec.ComputeHash(bt));
}
//--------------------------------------
private static string GetHexString(byte[] bt)
{
string s = string.Empty;
for (int i = 0; i < bt.Length; i++)
{
byte b = bt[i];
int n, n1, n2;
n = (int)b;
n1 = n & 15;
n2 = (n >> 4) & 15;
if (n2 > 9)
s += ((char)(n2 - 10 + (int)'A')).ToString();
else
s += n2.ToString();
if (n1 > 9)
s += ((char)(n1 - 10 + (int)'A')).ToString();
else
s += n1.ToString();
if ((i + 1) != bt.Length && (i + 1) % 2 == 0) s += "-";
}
return s;
}
//--------------------------------------
//Return a hardware identifier
private static string identifier(string wmiClass, string wmiProperty, string wmiMustBeTrue)
{
string result = "";
System.Management.ManagementClass mc = new System.Management.ManagementClass(wmiClass);
System.Management.ManagementObjectCollection moc = mc.GetInstances();
foreach (System.Management.ManagementObject mo in moc)
{
if (mo[wmiMustBeTrue].ToString() == "True")
{
//Only get the first one
if (result == "")
{
result = mo[wmiProperty].ToString();
break;
}
}
}
return result;
}
//--------------------------------------
//Return a hardware identifier
private static string identifier(string wmiClass, string wmiProperty)
{
string result = "";
System.Management.ManagementClass mc = new System.Management.ManagementClass(wmiClass);
System.Management.ManagementObjectCollection moc = mc.GetInstances();
foreach (System.Management.ManagementObject mo in moc)
{
//Only get the first one
if (result == "")
{
result = mo[wmiProperty].ToString();
break;
}
}
return result;
}
//--------------------------------------
private static string cpuId()
{
//Uses first CPU identifier available in order of preference
//Don't get all identifiers, as it is very time consuming
string retVal = identifier("Win32_Processor", "UniqueId");
if (retVal == "") //If no UniqueID, use ProcessorID
{
retVal = identifier("Win32_Processor", "ProcessorId");
if (retVal == "") //If no ProcessorId, use Name
{
retVal = identifier("Win32_Processor", "Name");
if (retVal == "") //If no Name, use Manufacturer
{
retVal = identifier("Win32_Processor", "Manufacturer");
}
}
}
return retVal;
}
//--------------------------------------
//BIOS Identifier
private static string biosId()
{
return identifier("Win32_BIOS", "Manufacturer")
+ identifier("Win32_BIOS", "SMBIOSBIOSVersion")
+ identifier("Win32_BIOS", "IdentificationCode")
+ identifier("Win32_BIOS", "SerialNumber")
+ identifier("Win32_BIOS", "ReleaseDate")
+ identifier("Win32_BIOS", "Version");
}
//--------------------------------------
//Motherboard ID
private static string baseId()
{
return identifier("Win32_BaseBoard", "Model")
+ identifier("Win32_BaseBoard", "Manufacturer")
+ identifier("Win32_BaseBoard", "Name")
+ identifier("Win32_BaseBoard", "SerialNumber");
}
//--------------------------------------
//Primary video controller ID
private static string videoId()
{
return identifier("Win32_VideoController", "Name");
}
}

Related

How to reverse serial data capture C#

I get this for Serial Port - 0xA8FEE988 0x00002F1F 0x00000000 0x00000000
Correct MAC is - this 88:E9:FE:A8:1F:2F
I want to know a correct way to organize.
string Data = "0xA8FEE988 0x00002F1F 0x00000000 0x00000000";
rtf.AppendTex(Mac_Reverso(Data));
public static string Mac_Reverso(string macAddress)
{
string macRevertido = string.Empty;
string s = macAddress.Replace("0x", "");
string[] macLista = s.Split(' ');
foreach (var mac in macLista)
{
for (var i = mac.Length; i > 0; i -= 2)
{
macRevertido += mac.Substring(i - 2, 2);
if (macRevertido.Length == 12)
{
return macRevertido;
}
}
}
return macRevertido; //op 88E9FE9DB3D2
}
A bit of an hacky way but you could do the following:
public static string Mac_Reverso(string macAddress)
{
string macRevertido = string.Empty;
string s = macAddress.Replace("0x", "");
string[] macLista = s.Split(' ');
foreach (var mac in macLista)
{
for (var i = mac.Length; i > 0; i -= 2)
{
macRevertido += mac.Substring(i - 2, 2) + ":";
if (macRevertido.Length >= 17)
{
return macRevertido.Substring(0, macRevertido.Length-1);
}
}
}
return macRevertido; //op 88E9FE9DB3D2
}

Why is my ID changing with internet connectivity?

I was following this tutorial to generate a unique hardware ID for system. The problem is that the ID generated is different when internet is connected, and different when internet is disconnected.
This is the code I'm using:
private static string fingerPrint = string.Empty;
public static string GetUniqueID()
{
if (string.IsNullOrEmpty(fingerPrint))
{
fingerPrint = GetHash("CPU " + cpuId() + "\nBIOS " +
biosId() + "\nBASE " + baseId()
+ "\nVIDEO " + videoId() +"\nMAC "+ macId()
);
}
return fingerPrint;
}
private static string GetHash(string s)
{
MD5 sec = new MD5CryptoServiceProvider();
ASCIIEncoding enc = new ASCIIEncoding();
byte[] bt = enc.GetBytes(s);
return GetHexString(sec.ComputeHash(bt));
}
private static string GetHexString(byte[] bt)
{
string s = string.Empty;
for (int i = 0; i < bt.Length; i++)
{
byte b = bt[i];
int n, n1, n2;
n = (int)b;
n1 = n & 15;
n2 = (n >> 4) & 15;
if (n2 > 9)
s += ((char)(n2 - 10 + (int)'A')).ToString();
else
s += n2.ToString();
if (n1 > 9)
s += ((char)(n1 - 10 + (int)'A')).ToString();
else
s += n1.ToString();
if ((i + 1) != bt.Length && (i + 1) % 2 == 0) s += "-";
}
return s;
}
private static string identifier
(string wmiClass, string wmiProperty, string wmiMustBeTrue)
{
string result = "";
System.Management.ManagementClass mc =
new System.Management.ManagementClass(wmiClass);
System.Management.ManagementObjectCollection moc = mc.GetInstances();
foreach (System.Management.ManagementObject mo in moc)
{
if (mo[wmiMustBeTrue].ToString() == "True")
{
//Only get the first one
if (result == "")
{
try
{
result = mo[wmiProperty].ToString();
break;
}
catch
{
}
}
}
}
return result;
}
private static string identifier(string wmiClass, string wmiProperty)
{
string result = "";
System.Management.ManagementClass mc =
new System.Management.ManagementClass(wmiClass);
System.Management.ManagementObjectCollection moc = mc.GetInstances();
foreach (System.Management.ManagementObject mo in moc)
{
if (result == "")
{
try
{
result = mo[wmiProperty].ToString();
break;
}
catch
{
}
}
}
return result;
}
private static string cpuId()
{
string retVal = identifier("Win32_Processor", "UniqueId");
if (retVal == "")
{
retVal = identifier("Win32_Processor", "ProcessorId");
if (retVal == "")
{
retVal = identifier("Win32_Processor", "Name");
if (retVal == "")
{
retVal = identifier("Win32_Processor", "Manufacturer");
}
retVal += identifier("Win32_Processor", "MaxClockSpeed");
}
}
return retVal;
}
private static string biosId()
{
return identifier("Win32_BIOS", "Manufacturer")
+ identifier("Win32_BIOS", "SMBIOSBIOSVersion")
+ identifier("Win32_BIOS", "IdentificationCode")
+ identifier("Win32_BIOS", "SerialNumber")
+ identifier("Win32_BIOS", "ReleaseDate")
+ identifier("Win32_BIOS", "Version");
}
private static string diskId()
{
return identifier("Win32_DiskDrive", "Model")
+ identifier("Win32_DiskDrive", "Manufacturer")
+ identifier("Win32_DiskDrive", "Signature")
+ identifier("Win32_DiskDrive", "TotalHeads");
}
private static string baseId()
{
return identifier("Win32_BaseBoard", "Model")
+ identifier("Win32_BaseBoard", "Manufacturer")
+ identifier("Win32_BaseBoard", "Name")
+ identifier("Win32_BaseBoard", "SerialNumber");
}
private static string videoId()
{
return identifier("Win32_VideoController", "DriverVersion")
+ identifier("Win32_VideoController", "Name");
}
private static string macId()
{
return identifier("Win32_NetworkAdapterConfiguration",
"MACAddress", "IPEnabled");
}
GetUniqueID() is the function which hashes the various IDs. Why is the ID generated different with and without internet?
I think its because when you are disconnected, your network interface is disabled and as such, it is unable to retrieve MAC address.
instead of this 1000s of lines of complex logic, can't you simple use MAC id of the device. It will remain same all the time or Device Serial Key that is Bios serial of the device. Bios key will be available even if there's no network.
My team once tried to build a similar piece of code to generate a unique id based off of machine settings without using persistent storage. E.g Hash(hostname, username, domain name, mac address, etc...). Seemed like a good idea at the time, but turns out to be inherently unreliable as some of the APIs that should be consistent at returning these values, aren't always so.
The simpler and more reliable approach is to generate a GUID and persist it to the registry (or file on disk, or even the Windows Credential Store).
static string GetUniqueID()
{
string result;
string registry_path = "HKEY_CURRENT_USER\\Software\\MyApp"; // substitue your own app name here
Object obj = Registry.GetValue(registry_path, "UniqueID", null);
if ((obj == null) || !(obj is string))
{
result = Guid.NewGuid().ToString();
Registry.SetValue(registry_path, "UniqueID", result);
}
else
{
result = (string)obj;
}
return result;
}
It's also faster than making WMI calls too.
I think you’ve picked a wrong tutorial.
MAC changes when you connect/disconnect due to the 2 reasons. First, most PCs have more than 1 network card, and the order in which they appear in WMI is undefined. Second, by default, Windows 10 sometimes randomizes WiFi MAC address each time you connect to a WiFi network
The rest of the IDs you’re using are not much better.
videoId is unstable because driver version will update when you update the driver, BTW some windows updates include new versions of GPU drivers
diskId is unstable because users plug USB flash drives or external hard drives.
cpuId is unreliable because it only include information specific to CPU model, i.e. for a mainstream CPU you’ll have many millions of people in the world with the same cpuId.

Generate Activation Key From Hardware ID

I am trying to implement Hardware locked Licensing.I found the following code from codeproject that generates hardware id(Machine ID)
This code generates Hardware Key
using System;
using System.Management;
using System.Security.Cryptography;
using System.Security;
using System.Collections;
using System.Text;
namespace Security
{
/// <summary>
/// Generates a 16 byte Unique Identification code of a computer
/// Example: 4876-8DB5-EE85-69D3-FE52-8CF7-395D-2EA9
/// </summary>
public class FingerPrint
{
private static string fingerPrint = string.Empty;
public static string Value()
{
if (string.IsNullOrEmpty(fingerPrint))
{
fingerPrint = GetHash("CPU >> " + cpuId() + "\nBIOS >> " +
biosId() + "\nBASE >> " + baseId()
//+"\nDISK >> "+ diskId() + "\nVIDEO >> " +
videoId() +"\nMAC >> "+ macId()
);
}
return fingerPrint;
}
private static string GetHash(string s)
{
MD5 sec = new MD5CryptoServiceProvider();
ASCIIEncoding enc = new ASCIIEncoding();
byte[] bt = enc.GetBytes(s);
return GetHexString(sec.ComputeHash(bt));
}
private static string GetHexString(byte[] bt)
{
string s = string.Empty;
for (int i = 0; i < bt.Length; i++)
{
byte b = bt[i];
int n, n1, n2;
n = (int)b;
n1 = n & 15;
n2 = (n >> 4) & 15;
if (n2 > 9)
s += ((char)(n2 - 10 + (int)'A')).ToString();
else
s += n2.ToString();
if (n1 > 9)
s += ((char)(n1 - 10 + (int)'A')).ToString();
else
s += n1.ToString();
if ((i + 1) != bt.Length && (i + 1) % 2 == 0) s += "-";
}
return s;
}
#region Original Device ID Getting Code
//Return a hardware identifier
private static string identifier
(string wmiClass, string wmiProperty, string wmiMustBeTrue)
{
string result = "";
System.Management.ManagementClass mc =
new System.Management.ManagementClass(wmiClass);
System.Management.ManagementObjectCollection moc = mc.GetInstances();
foreach (System.Management.ManagementObject mo in moc)
{
if (mo[wmiMustBeTrue].ToString() == "True")
{
//Only get the first one
if (result == "")
{
try
{
result = mo[wmiProperty].ToString();
break;
}
catch
{
}
}
}
}
return result;
}
//Return a hardware identifier
private static string identifier(string wmiClass, string wmiProperty)
{
string result = "";
System.Management.ManagementClass mc =
new System.Management.ManagementClass(wmiClass);
System.Management.ManagementObjectCollection moc = mc.GetInstances();
foreach (System.Management.ManagementObject mo in moc)
{
//Only get the first one
if (result == "")
{
try
{
result = mo[wmiProperty].ToString();
break;
}
catch
{
}
}
}
return result;
}
private static string cpuId()
{
//Uses first CPU identifier available in order of preference
//Don't get all identifiers, as it is very time consuming
string retVal = identifier("Win32_Processor", "UniqueId");
if (retVal == "") //If no UniqueID, use ProcessorID
{
retVal = identifier("Win32_Processor", "ProcessorId");
if (retVal == "") //If no ProcessorId, use Name
{
retVal = identifier("Win32_Processor", "Name");
if (retVal == "") //If no Name, use Manufacturer
{
retVal = identifier("Win32_Processor", "Manufacturer");
}
//Add clock speed for extra security
retVal += identifier("Win32_Processor", "MaxClockSpeed");
}
}
return retVal;
}
//BIOS Identifier
private static string biosId()
{
return identifier("Win32_BIOS", "Manufacturer")
+ identifier("Win32_BIOS", "SMBIOSBIOSVersion")
+ identifier("Win32_BIOS", "IdentificationCode")
+ identifier("Win32_BIOS", "SerialNumber")
+ identifier("Win32_BIOS", "ReleaseDate")
+ identifier("Win32_BIOS", "Version");
}
//Main physical hard drive ID
private static string diskId()
{
return identifier("Win32_DiskDrive", "Model")
+ identifier("Win32_DiskDrive", "Manufacturer")
+ identifier("Win32_DiskDrive", "Signature")
+ identifier("Win32_DiskDrive", "TotalHeads");
}
//Motherboard ID
private static string baseId()
{
return identifier("Win32_BaseBoard", "Model")
+ identifier("Win32_BaseBoard", "Manufacturer")
+ identifier("Win32_BaseBoard", "Name")
+ identifier("Win32_BaseBoard", "SerialNumber");
}
//Primary video controller ID
private static string videoId()
{
return identifier("Win32_VideoController", "DriverVersion")
+ identifier("Win32_VideoController", "Name");
}
//First enabled network card ID
private static string macId()
{
return identifier("Win32_NetworkAdapterConfiguration",
"MACAddress", "IPEnabled");
}
#endregion
}
}
.My aim is to implement strict licensing scheme.As shown in the diagram given below,I am able to generate a unique machine or Hardware ID using the above code.
Based on the Machine ID or Key,I wish to generate an Activation Key so that it would be unique and can be used only on one machine because the Activation key would be generated from that Machines MachineID
How can that be achieved?
Following is the image
I hope my doubt is clear.If not please let me know,I'll update the question with more information
The simple solution
The simple solution would be something like this. When the user buys your software, generate a unique GUID for the license. Let's call this the license key. When the user installs the software, you take your unique hardware key, concatenate that with the license key, and hash the result. The hash you generate will be the activation code that you're looking for. Store that value on your server. If the same license key is ever used to install the software on another machine, you will compare the computed activation code for that installation against the one you have stored on your server and deny the installation if the codes do not match.
The Catch
That being said... the way your current scheme is set up, you are going to risk making your customers very upset. For example, if I buy your software and my hard drive dies on me, with your current setup I would have no way to recover my software. If you're going to do hardware signature based licensing, you should try to restrict it to the features that are least likely to change. BIOS...ok maybe you're safe. But hard drive, network card, video card are much more likely to change.
Also, you might want to give your customers a way to transfer the license to another computer. The way your do this is have a custom action in your uninstaller that will revoke the activation code for the license so it will no longer be tied to that hardware ID.
Conclusion
In all of this, the key is to keep things as simple as possible for your customer. There obviously is a trade-off between security and ease of use, but you DO NOT want to lock out legitimate customers and risk alienating them.
All that being said, there are also plenty of existing commercials options for managing licenses. QLM is pretty good is you're willing to shell out the money. In everything, just consider the cost of securing your software versus the value of securing it.

I don't understand what I changed

One hour ago, I spend a lot of time and finished the project but I had problems when saving it properly and totally lost it. However, I did it again but this time it don't work
I am not sure what I did wrong this time... I think I did exactly the same, but this time don't work?
I am getting the following error:
Error 1 An object reference is required for the non-static field,
method, or property
'ConsoleApplication1.Program.convertir(string)' C:\Documents and
Settings\modifiedForPersonalReasons\Program.cs 12 45 ConsoleApplication1
Here is my code, I was going to put just the error lines but then it would probably miss some information that we could need to spot the problem:
static void Main(string[] args)
{
Console.WriteLine("23.21 es " + convertir("23.21"));
Console.ReadLine();
}
public string convertir(string str)
{
string[] arr;
arr = str.Split('.');
string rtn = españolizar(arr[0], "peso");
if (arr.Length > 1)
{
rtn += " con " + españolizar(arr[1], "centavo");
}
return rtn;
}
public string españolizar(string str, string str2)
{
string[] list1 = { "cero", "un", "dos", "tres", "cuatro", "cinco", "seis", "siete", "ocho", "nueve", "diez", "once", "doce", "trece", "catorce", "quince" };
string[] list2 = { "nivelarindexes", "dieci", "veinti", "trei", "cuare", "cincue", "sese", "sete", "oche", "nove" };
int numero = int.Parse(str);
string strNumero = Convert.ToString(numero);
int primerDigito = int.Parse(Convert.ToString(strNumero[0]));
int segundoDigito = 0;
if (strNumero.Length > 1)
{
segundoDigito = int.Parse(Convert.ToString(strNumero[1]));
}
int cases = -1;
if (numero > -1 && numero < 16)
{
cases = 0;
}
else if (numero > 15 && numero < 30)
{
cases = 1;
}
else if (numero > 29 && numero < 100)
{
cases = 2;
}
else if (numero == 100)
{
cases = 3;
}
string rtn = "";
switch (cases)
{
case 0:
rtn = list1[numero] + " " + str2;
if (primerDigito != 1)
{
rtn += "s";
}
break;
case 1:
if (numero != 20)
{
rtn = list2[primerDigito] + list1[segundoDigito];
}
else
{
rtn = "veinte";
}
rtn += " " + str2 + "s";
break;
case 2:
rtn = list2[primerDigito] + "nta";
if (segundoDigito != 0)
{
rtn += " y " + list1[segundoDigito];
}
rtn += " " + str2 + "s";
break;
case 3:
rtn = "cien " + str2 + "s";
break;
case -1:
rtn = "número invalido";
break;
}
rtn = rtn.Replace("iun", "iún").Replace("idos", "idós").Replace("itres", "itrés").Replace("iseis", "iséis");
return rtn;
}
I could swear I didn't change anything :C
Change public string convertir(string str) to public static string convertir(string str). Do the same for the españolizar function.
You are getting this message because you are calling non-static methods from a static method. You need an instance of this class to call the non-static methods, or make the other methods static.
You must change your two methods to static methods as you can't call a static method from a non-static method.
See here for an explanation as to why.
To fix this, you must change the following:
public string convertir(string str)
To
public static string convertir(string str)
And change
public string españolizar(string str, string str2)
To
public static string españolizar(string str, string str2)
The convertir method needs to be static (same as Main).

How to get mx records for a dns name with System.Net.DNS? [closed]

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
We don’t allow questions seeking recommendations for books, tools, software libraries, and more. You can edit the question so it can be answered with facts and citations.
Closed 1 year ago.
Improve this question
Is there any built in method in the .NET library that will return all of the MX records for a given domain? I see how you get CNAMES, but not MX records.
Update 2018/5/23:
Check out MichaC's answer for a newer library that has .NET standard support.
Original Answer:
The ARSoft.Tools.Net library by Alexander Reinert seems to do the job pretty well.
It's available from NuGet:
PM> Install-Package ARSoft.Tools.Net
Import the namespace:
using ARSoft.Tools.Net.Dns;
Then making a synchronous lookup is as simple as:
var resolver = new DnsStubResolver();
var records = resolver.Resolve<MxRecord>("gmail.com", RecordType.Mx);
foreach (var record in records) {
Console.WriteLine(record.ExchangeDomainName?.ToString());
}
Which gives us the output:
gmail-smtp-in.l.google.com.
alt1.gmail-smtp-in.l.google.com.
alt2.gmail-smtp-in.l.google.com.
alt3.gmail-smtp-in.l.google.com.
alt4.gmail-smtp-in.l.google.com.
Underneath the hood, it looks like the library constructs the UDP (or TCP) packets necessary to send to the resolver, like you might expect. The library even has logic (invoked with DnsClient.Default) to discover which DNS server to query.
Full documentation can be found here.
Just roled my own library because there was nothing for .net core / xplat support... https://github.com/MichaCo/DnsClient.NET
It works pretty great and gives you dig like log messages if you want.
Simple to use
var lookup = new LookupClient();
var result = await lookup.QueryAsync("google.com", QueryType.ANY);
and works with custom servers running on any ports, multiple servers, etc...
see also DnsClient Website for more details
I spent all day figuring out how to send/receive dns requests and came up with this. Its a complete generic handler. You just have to set the dns server and pass in 'd' eg. my.website.com?d=itmanx.com
<%# WebHandler Language="C#" Class="Handler" %>
using System;
using System.Web;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.Collections.Generic;
public class Handler : IHttpHandler
{
string dns = "dc1"; //change to your dns
string qtype = "15"; //A=1 MX=15
string domain = "";
int[] resp;
public void ProcessRequest(HttpContext context)
{
context.Response.ContentType = "text/plain";
try
{
if (context.Request["t"] != null) qtype = context.Request["t"];
if (context.Request["d"] != null) domain = context.Request["d"];
if (string.IsNullOrEmpty(domain)) throw new Exception("Add ?d=<domain name> to url or post data");
Do(context);
}
catch (Exception ex)
{
string msg = ex.Message;
if (msg == "1") msg = "Malformed packet";
else if (msg == "5") msg = "Refused";
else if (msg == "131") msg = "No such name";
context.Response.Write("Error: " + msg);
}
}
public void Do(HttpContext context)
{
UdpClient udpc = new UdpClient(dns, 53);
// SEND REQUEST--------------------
List<byte> list = new List<byte>();
list.AddRange(new byte[] { 88, 89, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0 });
string[] tmp = domain.Split('.');
foreach (string s in tmp)
{
list.Add(Convert.ToByte(s.Length));
char[] chars = s.ToCharArray();
foreach (char c in chars)
list.Add(Convert.ToByte(Convert.ToInt32(c)));
}
list.AddRange(new byte[] { 0, 0, Convert.ToByte(qtype), 0, 1 });
byte[] req = new byte[list.Count];
for (int i = 0; i < list.Count; i++) { req[i] = list[i]; }
udpc.Send(req, req.Length);
// RECEIVE RESPONSE--------------
IPEndPoint ep = null;
byte[] recv = udpc.Receive(ref ep);
udpc.Close();
resp = new int[recv.Length];
for (int i = 0; i < resp.Length; i++)
resp[i] = Convert.ToInt32(recv[i]);
int status = resp[3];
if (status != 128) throw new Exception(string.Format("{0}", status));
int answers = resp[7];
if (answers == 0) throw new Exception("No results");
int pos = domain.Length + 18;
if (qtype == "15") // MX record
{
while (answers > 0)
{
int preference = resp[pos + 13];
pos += 14; //offset
string str = GetMXRecord(pos, out pos);
context.Response.Write(string.Format("{0}: {1}\n", preference, str));
answers--;
}
}
else if (qtype == "1") // A record
{
while (answers > 0)
{
pos += 11; //offset
string str = GetARecord(ref pos);
context.Response.Write(string.Format("{0}\n", str));
answers--;
}
}
}
//------------------------------------------------------
private string GetARecord(ref int start)
{
StringBuilder sb = new StringBuilder();
int len = resp[start];
for (int i = start; i < start + len; i++)
{
if (sb.Length > 0) sb.Append(".");
sb.Append(resp[i + 1]);
}
start += len + 1;
return sb.ToString();
}
private string GetMXRecord(int start, out int pos)
{
StringBuilder sb = new StringBuilder();
int len = resp[start];
while (len > 0)
{
if (len != 192)
{
if (sb.Length > 0) sb.Append(".");
for (int i = start; i < start + len; i++)
sb.Append(Convert.ToChar(resp[i + 1]));
start += len + 1;
len = resp[start];
}
if (len == 192)
{
int newpos = resp[start + 1];
if (sb.Length > 0) sb.Append(".");
sb.Append(GetMXRecord(newpos, out newpos));
start++;
break;
}
}
pos = start + 1;
return sb.ToString();
}
//------------------------------------------------------
public bool IsReusable { get { return false; } }
}
My approach was to use nslookup.exe to retreive the MX record.
The solution is not as fancy as rewriting whole DNS or using a System DLL -> but it works, with a little amount of lines.
To get things right, this code >just works< it's not ressource efficient nor fast and has a lots of room for improvment (multiple hostnames, async, more usefull return value,adding the priority):
static List<string> GetMxRecords(string host){
ProcessStartInfo nslookup_config = new ProcessStartInfo("nslookup.exe");
nslookup_config.RedirectStandardInput = true;
nslookup_config.RedirectStandardOutput = true;
nslookup_config.RedirectStandardError = true;
nslookup_config.UseShellExecute = false;
var nslookup = Process.Start(nslookup_config);
nslookup.StandardInput.WriteLine("set q=mx");
nslookup.StandardInput.WriteLine(host);
nslookup.StandardInput.WriteLine("exit");
List<string> lines = new List<string>();
while (!nslookup.StandardOutput.EndOfStream)
{
string l = nslookup.StandardOutput.ReadLine();
if (l.Contains("internet address ="))
{
while (l.Contains("\t\t"))
{
l = l.Replace("\t\t", "\t");
}
lines.Add(l.Replace("\tinternet address = ","="));
}
}
nslookup.Close();
return lines;
}
Should be working international, since nslookup does not support any translation (I'm working on a German machine and I'm getting english output).
The result are strings like this:
alt4.gmail-smtp-in.l.google.com=74.125.28.27
alt2.gmail-smtp-in.l.google.com=74.125.200.27
alt1.gmail-smtp-in.l.google.com=209.85.233.26
gmail-smtp-in.l.google.com=66.102.1.27
alt3.gmail-smtp-in.l.google.com=108.177.97.27
The accepted answer doesn't work for .NET framework < 4.5, so would suggest that those of you who can't use ARSOFT.Tools can use DNDNs from https://dndns.codeplex.com
Given below is a console application that returns the MX record for a given domain modifying their examples.
using System;
using System.Net.Sockets;
using DnDns.Enums;
using DnDns.Query;
using DnDns.Records;
namespace DnDnsExamples
{
class Program
{
static void Main(string[] args)
{
DnsQueryRequest request3 = new DnsQueryRequest();
DnsQueryResponse response3 = request3.Resolve("gmail.com", NsType.MX, NsClass.INET, ProtocolType.Tcp);
OutputResults(response3);
Console.ReadLine();
}
private static void OutputResults(DnsQueryResponse response)
{
foreach (IDnsRecord record in response.Answers)
{
Console.WriteLine(record.Answer);
Console.WriteLine(" |--- RDATA Field Length: " + record.DnsHeader.DataLength);
Console.WriteLine(" |--- Name: " + record.DnsHeader.Name);
Console.WriteLine(" |--- NS Class: " + record.DnsHeader.NsClass);
Console.WriteLine(" |--- NS Type: " + record.DnsHeader.NsType);
Console.WriteLine(" |--- TTL: " + record.DnsHeader.TimeToLive);
Console.WriteLine();
}
}
}
}
Here is a Class I use to look up MX records only.
using System;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.Collections.Specialized;
namespace Mx.Dns
{
public class Query
{
//Build a DNS query buffer according to RFC 1035 4.1.1 e 4.1.2
private readonly int id;
private readonly int flags;
private readonly int QDcount;
private readonly int ANcount;
private readonly int NScount;
private readonly int ARcount;
private readonly string Qname;
private readonly int Qtype;
private readonly int Qclass;
public byte[] buf;
public Query(int ID, string query, int qtype)
{
//init vectors with given + default values
id = ID;
flags = 256;
QDcount = 1;
ANcount = 0;
NScount = 0;
ARcount = 0;
Qname = query;
Qtype = qtype;
Qclass = 1; //Internet = IN = 1
//build a buffer with formatted query data
//header information (16 bit padding
buf = new byte[12 + Qname.Length + 2 + 4];
buf[0] = (byte)(id / 256);
buf[1] = (byte)(id - (buf[0] * 256));
buf[2] = (byte)(flags / 256);
buf[3] = (byte)(flags - (buf[2] * 256));
buf[4] = (byte)(QDcount / 256);
buf[5] = (byte)(QDcount - (buf[4] * 256));
buf[6] = (byte)(ANcount / 256);
buf[7] = (byte)(ANcount - (buf[6] * 256));
buf[8] = (byte)(NScount / 256);
buf[9] = (byte)(NScount - (buf[8] * 256));
buf[10] = (byte)(ARcount / 256);
buf[11] = (byte)(ARcount - (buf[10] * 256));
//QNAME (RFC 1035 4.1.2)
//no padding
string[] s = Qname.Split('.');
int index = 12;
foreach (string str in s) {
buf[index] = (byte)str.Length;
index++;
byte[] buf1 = Encoding.ASCII.GetBytes(str);
buf1.CopyTo(buf, index);
index += buf1.Length;
}
//add root domain label (chr(0))
buf[index] = 0;
//add Qtype and Qclass (16 bit values)
index = buf.Length - 4;
buf[index] = (byte)(Qtype / 256);
buf[index + 1] = (byte)(Qtype - (buf[index] * 256));
buf[index + 2] = (byte)(Qclass / 256);
buf[index + 3] = (byte)(Qclass - (buf[index + 2] * 256));
}
}
public class C_DNSquery
{
public StringCollection result = new StringCollection();
public int Error = 0;
public string ErrorTxt = "undefined text";
public bool Done = false;
public UdpClient udpClient;
private string DNS;
private string Query;
private int Qtype;
public bool IS_BLACKLIST_QUERY = false;
public C_DNSquery(string IPorDNSname, string query, int type)
{
DNS = IPorDNSname;
Query = query;
Qtype = type;
}
public void doTheJob()
{
//check if provided DNS contains an IP address or a name
IPAddress ipDNS;
IPHostEntry he;
try {
//try to parse an IPaddress
ipDNS = IPAddress.Parse(DNS);
} catch (FormatException ) {
// Console.WriteLine(e);
//format error, probably is a FQname, try to resolve it
try {
//try to resolve the hostname
he = Dns.GetHostEntry(DNS);
} catch {
//Error, invalid server name or address
Error = 98;
ErrorTxt = "Invalid server name:" + DNS;
Done = true;
return;
}
//OK, get the first server address
ipDNS = he.AddressList[0];
}
//Query the DNS server
//our current thread ID is used to match the reply with this process
Query myQuery = new Query(System.Threading.Thread.CurrentThread.ManagedThreadId, Query, Qtype);
//data buffer for query return value
Byte[] recBuf;
//use UDP protocol to connect
udpClient = new UdpClient();
do {
try {
//connect to given nameserver, port 53 (DNS)
udpClient.Connect(DNS, 53);
//send query
udpClient.Send(myQuery.buf, myQuery.buf.Length);
//IPEndPoint object allow us to read datagrams..
//..selecting only packet coming from our nameserver and port
IPEndPoint RemoteIpEndPoint = new IPEndPoint(ipDNS, 53);
//Blocks until a message returns on this socket from a remote host.
recBuf = udpClient.Receive(ref RemoteIpEndPoint);
udpClient.Close();
} catch (Exception e) {
//connection error, probably a wrong server address
udpClient.Close();
Error = 99;
ErrorTxt = e.Message + "(server:" + DNS + ")";
Done = true;
return;
}
//repeat until we get the reply with our threadID
} while (System.Threading.Thread.CurrentThread.ManagedThreadId != ((recBuf[0] * 256) + recBuf[1]));
//Check the DNS reply
//check if bit QR (Query response) is set
if (recBuf[2] < 128) {
//response byte not set (probably a malformed packet)
Error = 2;
ErrorTxt = "Query response bit not set";
Done = true;
return;
}
//check if RCODE field is 0
if ((recBuf[3] & 15) > 0) {
//DNS server error, invalid reply
switch (recBuf[3] & 15) {
case 1:
Error = 31;
ErrorTxt = "Format error. The nameserver was unable to interpret the query";
break;
case 2:
Error = 32;
ErrorTxt = "Server failure. The nameserver was unable to process the query.";
break;
case 3:
Error = 33;
ErrorTxt = "Name error. Check provided domain name!!";
break;
case 4:
Error = 34;
ErrorTxt = "Not implemented. The name server does not support the requested query";
break;
case 5:
Error = 35;
ErrorTxt = "Refused. The name server refuses to reply for policy reasons";
break;
default:
Error = 36;
ErrorTxt = "Unknown. The name server error code was: " + Convert.ToString((recBuf[3] & 15));
break;
}
Done = true;
return;
}
//OK, now we should have valid header fields
int QDcnt, ANcnt, NScnt, ARcnt;
int index;
QDcnt = (recBuf[4] * 256) + recBuf[5];
ANcnt = (recBuf[6] * 256) + recBuf[7];
NScnt = (recBuf[8] * 256) + recBuf[9];
ARcnt = (recBuf[10] * 256) + recBuf[11];
index = 12;
//sometimes there are no erros but blank reply... ANcnt == 0...
if (ANcnt == 0) { // if blackhole list query, means no spammer !!//if ((ANcnt == 0) & (IS_BLACKLIST_QUERY == false))
//error blank reply, return an empty array
Error = 4;
ErrorTxt = "Empty string array";
Done = true;
return;
}
//Decode received information
string s1;
// START TEST
s1 = Encoding.ASCII.GetString(recBuf, 0, recBuf.Length);
// END TEST
if (QDcnt > 0) {
//we are not really interested to this string, just parse and skip
s1 = "";
index = parseString(recBuf, index, out s1);
index += 4; //skip root domain, Qtype and QClass values... unuseful in this contest
}
if (IS_BLACKLIST_QUERY) {
// get the answers, normally one !
// int the four last bytes there is the ip address
Error = 0;
int Last_Position = recBuf.Length - 1;
result.Add(recBuf[Last_Position - 3].ToString() + "." + recBuf[Last_Position - 2].ToString() + "." + recBuf[Last_Position - 1].ToString() + "." + recBuf[Last_Position].ToString());
Done = true;
return;
}
int count = 0;
//get all answers
while (count < ANcnt) {
s1 = "";
index = parseString(recBuf, index, out s1);
//Qtype
int QType = (recBuf[index] * 256) + recBuf[index + 1];
index += 2;
s1 += "," + QType.ToString();
//QClass
int QClass = (recBuf[index] * 256) + recBuf[index + 1];
index += 2;
s1 += "," + QClass.ToString();
//TTL (Time to live)
uint TTL = (recBuf[index] * 16777216u) + (recBuf[index + 1] * 65536u) + (recBuf[index + 2] * 256u) + recBuf[index + 3];
index += 4;
s1 += "," + TTL.ToString();
int blocklen = (recBuf[index] * 256) + recBuf[index + 1];
index += 2;
if (QType == 15) {
int MXprio = (recBuf[index] * 256) + recBuf[index + 1];
index += 2;
s1 += "," + MXprio.ToString();
}
string s2;
index = parseString(recBuf, index, out s2);
s1 += "," + s2;
result.Add(s1);
count++;
}
Error = 0;
Done = true;
}
private int parseString(byte[] buf, int i, out string s)
{
int len;
s = "";
bool end = false;
while (!end) {
if (buf[i] == 192) {
//next byte is a pointer to the string, get it..
i++;
s += getString(buf, buf[i]);
i++;
end = true;
} else {
//next byte is the string length
len = buf[i];
i++;
//get the string
s += Encoding.ASCII.GetString(buf, i, len);
i += len;
//check for the null terminator
if (buf[i] != 0) {
//not null, add a point to the name
s += ".";
} else {
//null char..the string is complete, exit
end = true;
i++;
}
}
}
return i;
}
private string getString(byte[] buf, int i)
{
string s = "";
int len;
bool end = false;
while (!end) {
len = buf[i];
i++;
s += Encoding.ASCII.GetString(buf, i, len);
i += len;
if (buf[i] == 192) {
i++;
s += "." + getString(buf, buf[i]);
return s;
}
if (buf[i] != 0) {
s += ".";
} else {
end = true;
}
}
return s;
}
}
}
Here is how you use it.
/// <summary>
/// Get the MX from the domain address.
/// </summary>
public static string getMXrecord(string domain)
{
domain = domain.Substring(domain.IndexOf('#') + 1);
string LocalDNS = GetDnsAdress().ToString();
Console.WriteLine("domain: " + domain);
// resolv the authoritative domain (type=2)
C_DNSquery DnsQry = new C_DNSquery(LocalDNS, domain, 2);
Thread t1 = new Thread(new ThreadStart(DnsQry.doTheJob));
t1.Start();
int timeout = 20;
while ((timeout > 0) & (!DnsQry.Done)) {
Thread.Sleep(100);
timeout--;
}
if (timeout == 0) {
if (DnsQry.udpClient != null) {
DnsQry.udpClient.Close();
}
t1.Abort();
DnsQry.Error = 100;
}
string[] ns1;
string MyNs = "";
if (DnsQry.Error == 0) {
ns1 = DnsQry.result[0].Split(',');
MyNs = ns1[4];
t1.Abort();
} else {
t1.Abort();
MyNs = LocalDNS;
}
// Resolve MX (type = 15)
DnsQry = new C_DNSquery(MyNs, domain, 15);
Thread t2 = new Thread(new ThreadStart(DnsQry.doTheJob));
t2.Start();
timeout = 20;
string TTL = "";
string MXName = "";
Int32 preference = 9910000;
while ((timeout > 0) & (!DnsQry.Done)) {
Thread.Sleep(100);
timeout--;
}
if (timeout == 0) {
if (DnsQry.udpClient != null) {
DnsQry.udpClient.Close();
}
t2.Abort();
DnsQry.Error = 100;
}
if (DnsQry.Error == 0) {
if (DnsQry.result.Count == 1) {
string[] ns2 = DnsQry.result[0].Split(',');
MXName = ns2[5];
TTL = ns2[3];
preference = Int32.Parse(ns2[4]);
Console.WriteLine("domaine: {0} MX: {1} time: {2} pref: {3} ttl: {4}", domain.Substring(domain.IndexOf('#') + 1), MXName,
DateTime.Now, preference, TTL);
} else {
for (int indns = 0; indns <= DnsQry.result.Count - 1; indns++) {
string[] ns2 = DnsQry.result[indns].Split(',');
if (Int32.Parse(ns2[4]) < preference) {
MXName = ns2[5];
TTL = ns2[3];
preference = Int32.Parse(ns2[4]);
Console.WriteLine("domain: {0} MX: {1} time: {2} pref: {3} ttl: {4}", domain.Substring(domain.IndexOf('#') + 1), MXName,
DateTime.Now, preference, TTL);
}
}
}
}
return MXName;
}
I wrote a simply URL for that means
https://devselz.com/social/sign/buttons/dashboard/default.aspx?a=ciee&email=emailaddresstocheckifexistsornot#anydomain.com
Do not abuse
Return 1 if email exists or may exist, 0 if not
Works great in order to check:
gmail and gmail pro (domains not #gmail) accounts.
hotmail
For others like yahoo always returns 1
You can use this open source library to do almost any kind of query you would usually need.
Usage:
DnsClient dnsClient = new DnsClient();
string mxDomain = dnsClient.ResolveMX("example.com");
string mxDomainIP = dnsClient.ResolveMX("example.com", true);
string mxDomainIPv6 = dnsClient.ResolveMX("example.com", true, true);

Categories