c#


C# Newbie: How do I fix this code to do a DNS lookup?


This is my first time using C#, so I'm very much out of my element. But I have faith that the wonderful people here at Stack Overflow can help me out! I've come up with the following code (below) based on some other pieces of code I found floating around on the internet. What I am trying to do is to look up all the "text" DNS records (TXT) of a given domain. I've started out simple, with a Console Application in Visual C# 2008 Express looking up the records for google.com. I'll worry about customizing the domain based on command line parameters later; for now I'd just like to get this working. Any DNS lookup tools can tell you that google.com has this DNS text record in their DNS:
v=spf1 include:_netblocks.google.com ip4:216.73.93.70/31 ip4:216.73.93.72/31 ~all
But unfortunately that's not what I'm getting. Here's my code:
namespace DnsUtils
{
using System;
using System.Collections;
using System.ComponentModel;
using System.Runtime.InteropServices;
using System.Text;
public class DnsTxt
{
[DllImport("dnsapi", EntryPoint = "DnsQuery_W", CharSet = CharSet.Unicode, SetLastError = true, ExactSpelling = true)]
private static extern int DnsQuery([MarshalAs(UnmanagedType.VBByRefStr)]ref string pszName, QueryTypes wType, QueryOptions options, int aipServers, ref IntPtr ppQueryResults, int pReserved);
[DllImport("dnsapi", CharSet = CharSet.Auto, SetLastError = true)]
private static extern void DnsRecordListFree(IntPtr pRecordList, int FreeType);
public static string[] GetTXTRecords(string domain)
{
IntPtr ptr1 = IntPtr.Zero;
IntPtr ptr2 = IntPtr.Zero;
TXTRecord recTxt;
if (Environment.OSVersion.Platform != PlatformID.Win32NT)
{
throw new NotSupportedException();
}
ArrayList list1 = new ArrayList();
UnicodeEncoding encoding = new UnicodeEncoding();
int num1 = DnsTxt.DnsQuery(ref domain, QueryTypes.DNS_TYPE_TEXT, QueryOptions.DNS_QUERY_BYPASS_CACHE, 0, ref ptr1, 0);
if (num1 != 0)
{
throw new Win32Exception(num1);
}
for (ptr2 = ptr1; !ptr2.Equals(IntPtr.Zero); ptr2 = recTxt.pNext)
{
recTxt = (TXTRecord)Marshal.PtrToStructure(ptr2, typeof(TXTRecord));
if (recTxt.wType == 16)
{
IntPtr pointerToAddressStringArray = Marshal.AllocHGlobal(IntPtr.Size);
IntPtr addressStringArray = Marshal.ReadIntPtr(pointerToAddressStringArray);
for (int i = 0; i < recTxt.dwStringCount; i++)
{
IntPtr addressCharArray = Marshal.ReadIntPtr(recTxt.pStringArray, i * 4);
int offset = 0;
ArrayList bytesList = new ArrayList();
byte newByte = Marshal.ReadByte(addressCharArray, offset++);
while (newByte != 0)
{
bytesList.Add(newByte);
newByte = Marshal.ReadByte(addressCharArray, offset++);
}
byte[] bytesArray = new byte[offset];
bytesList.CopyTo(bytesArray);
string textValue = encoding.GetString(bytesArray);
list1.Add(textValue);
}
Marshal.FreeHGlobal(pointerToAddressStringArray);
}
}
DnsTxt.DnsRecordListFree(ptr2, 0);
return (string[])list1.ToArray(typeof(string));
}
private enum QueryOptions
{
DNS_QUERY_ACCEPT_TRUNCATED_RESPONSE = 1,
DNS_QUERY_BYPASS_CACHE = 8,
DNS_QUERY_DONT_RESET_TTL_VALUES = 0x100000,
DNS_QUERY_NO_HOSTS_FILE = 0x40,
DNS_QUERY_NO_LOCAL_NAME = 0x20,
DNS_QUERY_NO_NETBT = 0x80,
DNS_QUERY_NO_RECURSION = 4,
DNS_QUERY_NO_WIRE_QUERY = 0x10,
DNS_QUERY_RESERVED = -16777216,
DNS_QUERY_RETURN_MESSAGE = 0x200,
DNS_QUERY_STANDARD = 0,
DNS_QUERY_TREAT_AS_FQDN = 0x1000,
DNS_QUERY_USE_TCP_ONLY = 2,
DNS_QUERY_WIRE_ONLY = 0x100
}
private enum QueryTypes
{
DNS_TYPE_TEXT = 16
}
[StructLayout(LayoutKind.Sequential)]
private struct TXTRecord
{
public IntPtr pNext;
public string pName;
public short wType;
public short wDataLength;
public int flags;
public int dwTtl;
public int dwReserved;
public int dwStringCount;
public IntPtr pStringArray;
}
static void Main(string[] args)
{
try
{
string[] s = DnsUtils.DnsTxt.GetTXTRecords("google.com");
foreach (string st in s)
{
Console.WriteLine("Value: {0}", st);
}
}
catch (Win32Exception e)
{
Console.WriteLine(e.Message);
}
Console.ReadLine();
}
}
}
When I run this code, it prints Value: ?. Now I'm hoping that this means it actually did the DNS query and got the results as expected, but I just screwed something up in the part where it tries to convert an IntPtr to an array of strings (because I'm guessing it's harder to debug the former). Anyways, have any suggestions? Can anyone see where I went awry? Thanks in advance.
This line looks a bit off to me:
IntPtr addressCharArray = Marshal.ReadIntPtr(recTxt.pStringArray, i * 4);
It looks like you'd be reading the first 4 bytes of the first string entry of the TXT record as an IntPtr. I think something like:
string s = Marshal.PtrToStringAuto(recTxt.pStringArray);
would get you the first entry. After that, I think something like:
IntPtr p = new IntPtr(recTxt.pStringArray.ToInt32() + sizeof(uint) * i);
string s = Marshal.PtrToStringAuto(p);
would get the remainders.
As a simpler alternative you could avoid dealing with all the COM interop by creating a new nslookup process and parsing the StandardOuput to grab what you need.
using System;
using System.Diagnostics;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
var startInfo = new ProcessStartInfo("nslookup");
startInfo.Arguments = "-type=TXT google.com";
startInfo.RedirectStandardOutput = true;
startInfo.UseShellExecute = false;
startInfo.WindowStyle = ProcessWindowStyle.Hidden;
using (var cmd = Process.Start(startInfo))
{
// This is where you grab the output from nslookup.
Console.WriteLine(cmd.StandardOutput.ReadToEnd());
}
Console.Read();
}
}
}

Related Links

Winform images (ResourceManager) not visible on Windows 10
Convert LINQ to SQL query
Transfer between aspx.cs and c# class
How to initialize HResult in XAML apps?
Different results between System.Security.SignedCms and BouncyCastle CmsSignedDataGenerator
Creating a Dictionary-like storage to keep metainformation about various Board states
How to get Trust Sign certificate in VSTO using VS 2013?
Save WindowState and restore it after reboot /relogin [duplicate]
lambda expression to query a collection by a collection
Not displaying data in the report
Save data to a datatable created in another class?
System.IO.File.Copy never overwrites
Setup ASP.NET Web API to do work on a specific thread
Updating a field through workflows, better approach?
Set ItemsSource of Control to another control's ItemsSource that is Static and set in Xaml
ElasticSearch - .NET NEST API building multiple aggregrations with object initialization API seems to create an incorrect request

Categories

HOME
oauth-2.0
ftp
packet
ibm
azure-database-mysql
hex
aggregate-functions
handlebars.js
google-api-oauth
genexus
angular-universal
core-data
sha1
project-reactor
aws-devicefarm
computation-theory
inline-assembly
devexpress-mvc
rvm
sasl
ballerinalang
large-files
bytebuffer
dynamics-ax-2012-r3
andengine
imageprocessor
powerbi-embedded
tunnel
android-geofence
repeat
azure-storage-files
abide
pygraphviz
uitextview
definition
rexx
pexpect
text-extraction
anonymous-function
google-chrome-storage
import.io
denodo
richtext
disassembly
ios-keyboard-extension
cardview
scanf
easy68k
virtualenvwrapper
jira-agile
jigsaw
normalisation
android-xmlpullparser
nsoperationqueue
avi
custom-build-step
std
dynamics-nav-2013
yfiles
wiql
gnu-sort
database-project
first-order-logic
jsoncpp
syncano
touch-typing
fxmlloader
azure-worker-roles
rails-migrations
ant-contrib
android-relativelayout
connections
class-library
fastcgi-mono-server
node-amqp
nop
nokogiri
google-checkout
screensharing
esi
teamsystem
shapado
zend-validate
virtual-printer
opendir
mediastreamsource
appointment
scala-designer
zend-acl
cons

Resources

Mobile Apps Dev
Database Users
javascript
java
csharp
php
android
MS Developer
developer works
python
ios
c
html
jquery
RDBMS discuss
Cloud Virtualization
Database Dev&Adm
javascript
java
csharp
php
python
android
jquery
ruby
ios
html
Mobile App
Mobile App
Mobile App