DNS lookup and reverse DNS lookup [Win2k and newer only]

Share your advanced PureBasic knowledge/code with the community.
freak
PureBasic Team
PureBasic Team
Posts: 5940
Joined: Fri Apr 25, 2003 5:21 pm
Location: Germany

DNS lookup and reverse DNS lookup [Win2k and newer only]

Post by freak »

Uses the Windows DnsApi.dll, which is present in Windows 2000 and newer only.
Allows to get the IP for a name, and the name for an IP:

Code: Select all

#DNS_TYPE_A          = $0001      ; //  1
#DNS_TYPE_NS         = $0002      ; //  2
#DNS_TYPE_MD         = $0003      ; //  3
#DNS_TYPE_MF         = $0004      ; //  4
#DNS_TYPE_CNAME      = $0005      ; //  5
#DNS_TYPE_SOA        = $0006      ; //  6
#DNS_TYPE_MB         = $0007      ; //  7
#DNS_TYPE_MG         = $0008      ; //  8
#DNS_TYPE_MR         = $0009      ; //  9
#DNS_TYPE_NULL       = $000a      ; //  10
#DNS_TYPE_WKS        = $000b      ; //  11
#DNS_TYPE_PTR        = $000c      ; //  12
#DNS_TYPE_HINFO      = $000d      ; //  13
#DNS_TYPE_MINFO      = $000e      ; //  14
#DNS_TYPE_MX         = $000f      ; //  15
#DNS_TYPE_TEXT       = $0010      ; //  16

#DNS_QUERY_STANDARD                  = $00000000
#DNS_QUERY_ACCEPT_TRUNCATED_RESPONSE = $00000001
#DNS_QUERY_USE_TCP_ONLY              = $00000002
#DNS_QUERY_NO_RECURSION              = $00000004
#DNS_QUERY_BYPASS_CACHE              = $00000008

#DNS_QUERY_NO_WIRE_QUERY             = $00000010
#DNS_QUERY_NO_LOCAL_NAME             = $00000020
#DNS_QUERY_NO_HOSTS_FILE             = $00000040
#DNS_QUERY_NO_NETBT                  = $00000080

#DNS_QUERY_WIRE_ONLY                 = $00000100
#DNS_QUERY_RETURN_MESSAGE            = $00000200

#DNS_QUERY_TREAT_AS_FQDN             = $00001000
#DNS_QUERY_DONT_RESET_TTL_VALUES     = $00100000
#DNS_QUERY_RESERVED                  = $ff000000

Enumeration ; DNS_FREE_TYPE
  #DnsFreeFlat = 0
  #DnsFreeRecordList
  #DnsFreeParsedMessageFields
EndEnumeration 

Structure DNS_A_DATA
  IpAddress.l
EndStructure

Structure DNS_PTR_DATAA
  *pNameHost
EndStructure

Structure DNS_RECORD 
  *pNext.DNS_RECORD;  
  pName.s
  wType.w
  wDataLength.w
  StructureUnion
    DW.l 
    S.l
  EndStructureUnion
  dwTtl.l
  dwReserved.l
  
  ; Note: The Union def is incomplete. see DNS_RECORD in the psdk for more fields
  StructureUnion
    A.DNS_A_DATA 
    PTR.DNS_PTR_DATAA
    CNAME.DNS_PTR_DATAA
  EndStructureUnion 
EndStructure

Prototype DnsQuery_W(Name.p-unicode, wType.w, fOptions.l, *aopServers, *ppQueryResultSet, *pReserved)
Prototype DnsRecordListFree(*RecordList, FreeType)
Global DnsQuery_W.DnsQuery_W, DnsRecordListFree.DnsRecordListFree

; =========================================================

; Load the Dnsapi.dll. Use it just like OpenLibrary()
; Library is the #Library number for the new lib (can be #PB_Any)
;
Procedure LoadDnsApi(Library)
  Protected Result

  Result = OpenLibrary(Library, "Dnsapi.dll")
  If Result
    If Library = #PB_Any
      Library = Result
    EndIf
    
    DnsQuery_W        = GetFunction(Library, "DnsQuery_W")
    DnsRecordListFree = GetFunction(Library, "DnsRecordListFree")    
    
    If DnsQuery_W = 0 Or  DnsRecordListFree = 0
      CloseLibrary(Library)
      Result = 0
    EndIf      
  EndIf

  ProcedureReturn Result
EndProcedure

; Get the IP for the server name
; returns 0 on failure
;
Procedure.l DnsQuery(ServerName$)
  Protected IP = 0, CName$, *Record.DNS_RECORD
  
  If DnsQuery_W And DnsRecordListFree
    If DnsQuery_W(ServerName$, #DNS_TYPE_A, #DNS_QUERY_STANDARD, #Null, @*Record.DNS_RECORD, #Null) = 0 And *Record
      If *Record\wType = #DNS_TYPE_A ; dns record
        IP = *Record\A\IpAddress
      ElseIf *Record\wType = #DNS_TYPE_CNAME ; redirection
        CName$ = PeekS(*Record\CNAME\pNameHost, -1, #PB_Unicode)
        If CName$
          IP = DnsQuery(CName$)
        EndIf
      EndIf 
      DnsRecordListFree(*Record, #DnsFreeRecordList)
    EndIf
  EndIf
  
  ProcedureReturn IP
EndProcedure

; Get the name for the given IP
; returns "" on failure
;
Procedure.s ReverseDnsQuery(IP.l)
  Protected Name$ = "", *Record.DNS_RECORD
  Protected Query$ = Str((IP>>24) & $FF)+"."+Str((IP>>16) & $FF)+"."+Str((IP>>8) & $FF)+"."+Str(IP & $FF)+".IN-ADDR.ARPA" ; ip must be reversed!
  
  If DnsQuery_W And DnsRecordListFree
    If DnsQuery_W(Query$, #DNS_TYPE_PTR, #DNS_QUERY_STANDARD, #Null, @*Record.DNS_RECORD, #Null) = 0 And *Record
      If *Record\wType = #DNS_TYPE_PTR
        Name$ = PeekS(*Record\PTR\pNameHost, -1, #PB_Unicode)
      EndIf 
      DnsRecordListFree(*Record, #DnsFreeRecordList)
    EndIf
  EndIf
  
  ProcedureReturn Name$  
EndProcedure

; =========================================================
; Example
;

If LoadDnsApi(0)

  ip = DnsQuery("www.google.com")
  If ip
    Debug "IP lookup: " + IPString(ip)
    
    Name$ = ReverseDnsQuery(ip)
    If Name$
      Debug "Name lookup: " + Name$
    Else
      Debug "Reverse lookup failed."
    EndIf    
  Else
    Debug "IP lookup failed."
  EndIf
    
  CloseLibrary(0)
Else
  Debug "loading failed"
EndIf


Some info for those intrested:
http://msdn2.microsoft.com/en-us/library/ms682016.aspx
http://support.microsoft.com/kb/831226
http://support.microsoft.com/kb/164213
quidquid Latine dictum sit altum videtur
SFSxOI
Addict
Addict
Posts: 2970
Joined: Sat Dec 31, 2005 5:24 pm
Location: Where ya would never look.....

Post by SFSxOI »

Thanks freak :)

crashes here though
freak
PureBasic Team
PureBasic Team
Posts: 5940
Joined: Fri Apr 25, 2003 5:21 pm
Location: Germany

Post by freak »

where exactly?
quidquid Latine dictum sit altum videtur
SFSxOI
Addict
Addict
Posts: 2970
Joined: Sat Dec 31, 2005 5:24 pm
Location: Where ya would never look.....

Post by SFSxOI »

Don't know yet, Vista just gives me a 'PureBasic0.exe has stopped working' message. I'm still playing around with it, I think it may have something to do with the way the library is opened right now.
rsts
Addict
Addict
Posts: 2736
Joined: Wed Aug 24, 2005 8:39 am
Location: Southwest OH - USA

Post by rsts »

Same thing here with Vista and PB 4.02.

Vista returns a message that the program has stopped working.

edit - additional info from Vista

Problem signature:
Problem Event Name: APPCRASH
Application Name: ip.exe
Application Version: 0.0.0.0
Application Timestamp: 45d9b355
Fault Module Name: StackHash_3961
Fault Module Version: 6.0.6000.16386
Fault Module Timestamp: 4549bdc9
Exception Code: c0000374
Exception Offset: 000af1c9
OS Version: 6.0.6000.2.0.0.256.6
Locale ID: 1033
Additional Information 1: 3961
Additional Information 2: 780507ea6995f64959e5f38e88e6fbdf
Additional Information 3: 3768
Additional Information 4: be99c2ef83ab62150641370e59e9c206
SFSxOI
Addict
Addict
Posts: 2970
Joined: Sat Dec 31, 2005 5:24 pm
Location: Where ya would never look.....

Post by SFSxOI »

yep, my additional info:

Problem signature:
Problem Event Name: APPCRASH
Application Name: PureBasic1.exe
Application Version: 0.0.0.0
Application Timestamp: 45d9cd9a
Fault Module Name: StackHash_76e4
Fault Module Version: 6.0.6000.16386
Fault Module Timestamp: 4549bdc9
Exception Code: c0000374
Exception Offset: 000af1c9
OS Version: 6.0.6000.2.0.0.256.1
Locale ID: 1033
Additional Information 1: 76e4
Additional Information 2: e739c4499929e2f8aeb606773851bed5
Additional Information 3: 9a41
Additional Information 4: da5abb217cac02cd19b8e54be6389f90
User avatar
Psychophanta
Always Here
Always Here
Posts: 5153
Joined: Wed Jun 11, 2003 9:33 pm
Location: Anare
Contact:

Post by Psychophanta »

Thank you Timo, works fine here (WinXP pro)
http://www.zeitgeistmovie.com

while (world==business) world+=mafia;
SFSxOI
Addict
Addict
Posts: 2970
Joined: Sat Dec 31, 2005 5:24 pm
Location: Where ya would never look.....

Post by SFSxOI »

OK, I did a quick wrapper for the functions in dnsapi.dll, and then called the functions directly after rem'd the load library section in your code; I get an error here:

If DnsQuery_W(ServerName$, #DNS_TYPE_A, #DNS_QUERY_STANDARD, #Null, @*Record.DNS_RECORD, #Null) = 0 And *Record

says: 'Bad Parameter Type, number expected instead of string'

OK, some changes for Vista, from the wrapper containing the exported functions, just gussing here:

DnsRecordListFree(a.l,b.l,c.l,d.l) - now takes four parameters in Vista, not the two shown in the MSDN. The actual function in the Vista dnsapi.dll takes four parameters. For Vista I think it's not documented correctly in the MSDN.

DnsQuery_W - seems to have changed a little in Vista. In Vista it takes a pointer to the string. The MSDN doesn't document this for Vista but look at the parameter for CE5 at http://msdn2.microsoft.com/fr-fr/library/aa450336.aspx - see where its PCWSTR pszName - Vista implements the CE5 version it seems.

So...the way its coded now works with 2K and WinXP but not Vista.
RichardL
Enthusiast
Enthusiast
Posts: 532
Joined: Sat Sep 11, 2004 11:54 am
Location: UK

Post by RichardL »

Hi,
I'm a network newbie, and have written a client / server application that works (does not crash often!). I needed a DNS lookup and found Freak's code; which worked first go on my XP machine but I freely admit I'm floundering when it comes to understanding exactly how it works.

I then checked it out on a Vista laptop and got the problems mentioned earlier.

Has anyone got a fix?

Thanks in advance...

RichardL
alokdube
Enthusiast
Enthusiast
Posts: 148
Joined: Fri Nov 02, 2007 10:55 am
Location: India
Contact:

MX stuff

Post by alokdube »

Some code snippet working for MX queries:

Code: Select all


Procedure.s MXQuery(DomainName$) 
  Protected IP = 0, Name$, *Record.DNS_RECORD 
  
  If DnsQuery_W And DnsRecordListFree 
    If DnsQuery_W(DomainName$, #DNS_TYPE_MX, #DNS_QUERY_STANDARD, #Null, @*Record.DNS_RECORD, #Null) = 0 And *Record 
      If *Record\wType = #DNS_TYPE_MX ; dns record  
        Name$ = PeekS(*Record\MX\pNameExchange, -1, #PB_Unicode) 
   ;       Debug "Name: " + Name$
       EndIf 
      EndIf 
      DnsRecordListFree(*Record, #DnsFreeRecordList) 
   EndIf 

  
  ProcedureReturn Name$
EndProcedure
Last edited by alokdube on Mon Oct 20, 2008 8:27 am, edited 1 time in total.
alokdube
Enthusiast
Enthusiast
Posts: 148
Joined: Fri Nov 02, 2007 10:55 am
Location: India
Contact:

Post by alokdube »


DnsQuery_W - seems to have changed a little in Vista. In Vista it takes a pointer to the string. The MSDN doesn't document this for Vista but look at the parameter for CE5 at http://msdn2.microsoft.com/fr-fr/library/aa450336.aspx - see where its PCWSTR pszName - Vista implements the CE5 version it seems.

So...the way its coded now works with 2K and WinXP but not Vista.
I doubt if PCWSTR and PCSTR would matter
http://msdn2.microsoft.com/en-us/library/aa383751.aspx

PCSTR is 8 bit string and PCWSTR is 16bit string
alokdube
Enthusiast
Enthusiast
Posts: 148
Joined: Fri Nov 02, 2007 10:55 am
Location: India
Contact:

quick code that works on vista

Post by alokdube »

Code: Select all

InitNetwork()
;ExamineIPAddresses()
;IP$=IPString(NextIPAddress())
;Debug IP$
Compiler = RunProgram("nslookup", "purebasic.fr.", "", #PB_Program_Hide|#PB_Program_Open|#PB_Program_Read)
  Output$ = ""
  If Compiler  
    While ProgramRunning(Compiler)
      Output$=ReadProgramString(Compiler)
      ;Debug Output$
      If FindString(Output$,"Address:",1)
      name$=RemoveString(Output$,"Address:",1)
      ;Debug name$
      EndIf
    Wend    
    MessageRequester("title",name$)
  EndIf
seems like the easiest way to use things.
User avatar
pdwyer
Addict
Addict
Posts: 2813
Joined: Tue May 08, 2007 1:27 pm
Location: Chiba, Japan

Post by pdwyer »

Seems others outside PB are seeing this too :

http://forums.microsoft.com/MSDN/ShowPo ... 1&SiteID=1

I use freaks code, works well for me. I haven't tried it on vista though
Paul Dwyer

“In nature, it’s not the strongest nor the most intelligent who survives. It’s the most adaptable to change” - Charles Darwin
“If you can't explain it to a six-year old you really don't understand it yourself.” - Albert Einstein
alokdube
Enthusiast
Enthusiast
Posts: 148
Joined: Fri Nov 02, 2007 10:55 am
Location: India
Contact:

vista

Post by alokdube »

the code does crash on vista, after trying all possible msdn docs, this seemed like the easiest way to move on in life
User avatar
pdwyer
Addict
Addict
Posts: 2813
Joined: Tue May 08, 2007 1:27 pm
Location: Chiba, Japan

Post by pdwyer »

I don't use vista and don't know many people personally who do so I'm fine. I suspect people with large user bases would be impacted though

Personally though, I don't like those kinds of fixes to enumerate other cmdline apps and steal their text. I've seen people do that with pings too. You usually hit systems that have cmdline customised for some reason and then everything breaks. (are you sure all languages use the text "Address:" ? things like that)

I'd like to see Resolve functions in the network lib eventually for propper cross OS code but till then I think API calls are the correct way to go.

There must be a way to get this to work, I can't believe that vista SP1 has a bug that the DNS API can't resolve without crashing. There must be another way of doing this, a different API or something
Paul Dwyer

“In nature, it’s not the strongest nor the most intelligent who survives. It’s the most adaptable to change” - Charles Darwin
“If you can't explain it to a six-year old you really don't understand it yourself.” - Albert Einstein
Post Reply