Code archives/Networking/Query an DNS Server
This code has been declared by its author to be Public Domain code.
Download source code
| |||||
| This are some main function to directly query an Name server Its written in BlitzPlus ... bt can be used with any Blitz version (just remove the GUI-Functions) currently supported is the question for A - the ip of a domain MX - the mailhost for a domain PTR is still not working ... will add this soon maybe someon else got more luck then me ! If you solve the PTR Problem or got any questions write to: rayzor-s-edge@... | |||||
;To Do's
;
;buffer overrun while pointer is leaving the bank
;
;this code is far fom completed but its works real well
;still have problems with PTR
;if you have questions please write to rayzor-s-edge@gmx.net
Global DNS_queryid ;an unique id for dns querys (will be incred by each request)
Global DNS_stream ;the main DNS Stream (UDP port 53)
Global pointer ;the main pointer for parsing the streams
Dim splitresult$(100)
Type query
Field id
Field nserver
Field qr
Field opcode
Field aa
Field tc
Field rd
Field ra
Field z
Field rcode
Field stream
Field qname$
Field qtype
Field qclass
Field qsize
End Type
;create a window with a text area to show the results
hwnd=CreateWindow("text",0,0,500,600)
Global tarea=CreateTextArea(0,0,ClientWidth(hwnd),ClientHeight(hwnd),hwnd)
font = LoadFont("courier",14)
SetTextAreaFont(tarea,font)
SetGadgetLayout(tarea,1,1,1,1)
DNS_init() ;init the stream
DNS_Query(12345,parseip("212.79.208.3"),"www.google.de","A") ;ask your question
timer = CreateTimer(50)
Repeat
WaitTimer(timer)
Select WaitEvent()
Case $803
End
End Select
bank = DNS_waitQuery()
If bank Then DNS_readQuery(bank)
Forever
Function DNS_init()
;init first to get the udp stream
DNS_Stream = CreateUDPStream(53)
End Function
Function DNS_waitQuery()
;this function waits for an answer with the given id
;or the timeout
;this function parses all incoming querys but if the
;query is not the coresponding one it reactivates itself with
;a lowered timeout value
If Not RecvUDPMsg(DNS_stream) Then Return False
avail = ReadAvail(DNS_stream)
If Not avail Return False
Print "receiving a query "+avail+" bytes long"
;read the incomming stream
bank = CreateBank(avail)
ReadBytes(bank,DNS_stream,0,avail)
Return bank
End Function
Function DNS_Query(id,nserver,url$,typ$,class=1,rec=1)
;this function builds the query structure and
;feeds this structure with paramters
q.query = New query
queryid = id
q\id = queryid
q\qname = url
q\qclass = class
q\nserver = nserver
If rec Then q\rd = 1
Select Upper(typ)
Case "A"
q\qtype = 1
Case "PTR"
q\qtype = 12
Case "MX"
q\qtype = 15
End Select
;here the query structure is converted to an sendable stream
DNS_createquerystream(q)
;now send it and flush the structure
If Not DNS_sendquery(q)
Delete q
Return False
Else
Delete q
Return True
EndIf
End Function
Function DNS_createquerystream(q.query)
;this function converts the query structure to an real query streambank
q\stream = CreateBank(512)
;will not be reversed to little endian for fast lookup
PokeShort(q\stream,0,q\id)
b = q\rd Shl 8
lePokeShort(q\stream,2,b)
lePokeShort(q\stream,4,1)
lePokeShort(q\stream,6,0)
lePokeShort(q\stream,8,0)
lePokeShort(q\stream,10,0)
off = 12
Length = Len(q\qname)
nr = split(".",q\qname$)
For i=0 To nr-1
n$ = splitresult(i)
l = Len(n)
PokeByte(q\stream,off,l)
off = off + 1
For i2=1 To l
c$ = Mid(n,i2,1)
PokeByte(q\stream,off,Asc(c$))
off=off+1
Next
Next
PokeByte(q\stream,off,0)
off=off+1
lePokeShort(q\stream,off,q\qType)
off=off+2
lePokeShort(q\stream,off,q\qclass)
off=off+2
q\qsize = off
End Function
Function DNS_sendquery(q.query)
;this function sends the query streambank to the name server specified in tzhe query structure
If Not DNS_stream Then Return False
WriteBytes(q\stream,DNS_Stream,0,q\qsize)
SendUDPMsg(DNS_Stream,q\nserver,53)
Print "Query send to "+DottedIP(q\nserver)
Return True
End Function
Function DNS_ReadQuery(bank)
;this is a lot of parsing
If Not bank Then RuntimeError("invalid bank")
Print "-- HEADER --"
pointer = 12
id = PeekShort(bank,0)
Print "ID: "+id
flag = lePeekShort(bank,2)
Print "Flag: "+Right(Bin(flag),16)
qr = (flag Shr 15) And 1
opcode = (flag Shr 11) And 7
aa = (flag Shr 10) And 1
tc = (flag Shr 9) And 1
rd = (flag Shr 8) And 1
ra = (flag Shr 7) And 1
z = (flag Shr 4) And 7
rcode = (flag Shr 0) And 11
Print "HEADER IN DETAILS"
Print ""
Write "Msg Type: "
If qr
Print "Answer"
Else
Print "Question"
EndIf
Write "OpCode: "
Select opcode
Case 0
Print "standart"
Case 1
Print "inverse query"
Case 2
Print "a server status request"
Case 3
Print "reserved for future use"
End Select
Write "Authoritive: "
If aa
Print "Yes"
Else
Print "No"
EndIf
Write "Truncate: "
If tc
Print "Yes"
Else
Print "No"
EndIf
Write "Recursive desired: "
If rd
Print "Yes"
Else
Print "No"
EndIf
Write "Recursive available: "
If ra
Print "Yes"
Else
Print "No"
EndIf
Print "ZCode: "+z
Write "RCode: "
Select opcode
Case 0
Print "No error condition"
Case 1
Print "Format Error"
Case 2
Print "Server failure"
Case 3
Print "Name Error"
Case 4
Print "Not Implemented"
Case 5
Print "Refused"
Case 6
Print "Unkown"
End Select
qd = lePeekShort(bank,4)
an = lePeekShort(bank,6)
ns = lePeekShort(bank,8)
ar = lePeekShort(bank,10)
Print ""
Print "DATA COUNT"
Print ""
Print "Questions : "+qd
Print "Answers : "+an
Print "Athority : "+ns
Print "Additional: "+ar
Print ""
Print "-- DATA --"
For i=1 To qd
Print""
Print "READING QUESTION "+i+"("+pointer+")"
DNS_readqd(bank)
Next
For i=1 To an
Print""
Print "READING ANSWER "+i+"("+pointer+")"
DNS_readresource(bank)
Next
For i=1 To ns
Print""
Print "READING AUTHORITY "+i+"("+pointer+")"
DNS_readresource(bank)
Next
For i=1 To ar
Print""
Print "READING ADDITIONAL "+i+"("+pointer+")"
DNS_readresource(bank)
Next
End Function
Function DNS_readresource(bank)
;this function parses the resource messages
;resource messages are all appending message of a query
;except the question messages
name$ = DNS_decodeSubString(bank,pointer)
Local b[10]
For i=1 To 10
b[i]=PeekByte(bank,pointer)
pointer = pointer + 1
Next
ctype = (b[1] Shl 8) + b[2]
class = (b[3] Shl 8) + b[4]
ttl = (b[5] Shl 24) + (b[6] Shl 16) + (b[7] Shl 8) + b[8]
rdlength = (b[9] Shl 8) + b[10]
Print "NAME :"+name$
Print "TYPE :"+ctype
Print "CLASS :"+class
Print "TTL :"+ttl+" sec"
Print "RD Length:"+rdlength
repointer = pointer
Print ""
Select ctype
Case 1
Print "Data is a host address"
ip$ = decodeIPadress(bank,pointer)
Print "RDATA :"+ip
Case 2
Print "Data is an authoritative name server "
txt$ = DNS_decodeSubString(bank,pointer)
Print "RDATA :"+txt
Case 6
Print "Data is a zone of authority"
txt = DNS_decodeSubString(bank,pointer)
Print "MNAME :"+txt
txt = DNS_decodeSubString(bank,pointer)
Print "RNAME :"+txt
r1 = lePeekShort(bank,pointer)
pointer=pointer+2
r2 = lePeekShort(bank,pointer)
pointer=pointer+2
Print "SERIAL :"+(r1 Shl 16)+r2
r1 = lePeekShort(bank,pointer)
pointer=pointer+2
r2 = lePeekShort(bank,pointer)
pointer=pointer+2
Print "REFRESH :"+(r1 Shl 16)+r2
r1 = lePeekShort(bank,pointer)
pointer=pointer+2
r2 = lePeekShort(bank,pointer)
pointer=pointer+2
Print "RETRY :"+(r1 Shl 16)+r2
r1 = lePeekShort(bank,pointer)
pointer=pointer+2
r2 = lePeekShort(bank,pointer)
pointer=pointer+2
Print "EXPIRE :"+(r1 Shl 16)+r2
r1 = lePeekShort(bank,pointer)
pointer=pointer+2
r2 = lePeekShort(bank,pointer)
pointer=pointer+2
Print "MINIMUM :"+(r1 Shl 16)+r2
Case 12
Print "Data is a domain name pointer"
txt = DNS_decodeSubString(bank,pointer)
Print "RDATA :"+txt
Case 15
Print "Data is a mail exchange"
pre = lePeekShort(bank,pointer)
pointer = pointer + 2
Print "RDATA :"+pre
domain$ = DNS_decodeSubString(bank,pointer)
Print "RDATA :"+domain
Default
Print "Data is a unknown type"
End Select
pointer = repointer + rdlength
End Function
Function DNS_decodeSubString$(bank,off)
;this is the main subroutine for parsing
;it supports the query compression sheme
;for DNS querys
l = True
While l
l = PeekByte(bank,off)
off = off + 1
If l=0
pointer = off
Return Left(txt$,Len(txt)-1)
ElseIf (l And 192)=192
b1 = l
b2 = PeekByte(bank,off)
off = off + 1
off2 = (b1 Shl 8) + b2
off2 = (off2 And 16383)
; Print "(jumping to "+off2+")"
txt = txt + DNS_decodeSubString(bank,off2)
pointer = off
Return txt$
Else
For i = 1 To l
b = PeekByte(bank,off)
off = off + 1
txt$ = txt$ + Chr(b)
Next
txt$ = txt$ + "."
EndIf
Wend
End Function
Function DNS_Readqd(bank)
;this function parses question messages
txt$ = DNS_decodeSubString(bank,pointer)
Local b[4]
For i=1 To 4
b[i]=PeekByte(bank,pointer)
pointer = pointer + 1
Next
Print "QNAME :"+txt
Print "QTYPE :"+(b[1] Shl 8) + b[2]
Print "QCLASS:"+(b[3] Shl 8) + b[4]
End Function
Function decodeIPadress$(bank,off)
For i = 1 To 4
txt$ = txt + dot$ + PeekByte(bank,off)
dot$ = "."
off = off + 1
Next
Return txt
End Function
;------------------------------------------------------------- HELP FUNCTIONS
Function split(seperator$,txt$)
;splits an string with the given seperator and returns the nr of pieces
;the pieces can be found in the "splitresult" Array
pos=Instr(txt$,seperator$,1)
While (pos)
splitresult(count)=Left(txt$,pos-Len(seperator))
txt$=Right(txt$,Len(txt$)-pos-Len(seperator)+1)
pos=Instr(txt$,seperator$,1)
count=count+1
Wend
splitresult(count)=txt$
count=count+1
Return count
End Function
Function parseip(txt$)
;converts an dotted ip like "192.0.0.1" to an integervalue
nr = split(".",txt)
If nr = 4
b1 = Int(splitresult(0)) Shl 24
b2 = Int(splitresult(1)) Shl 16
b3 = Int(splitresult(2)) Shl 8
b4 = Int(splitresult(3)) Shl 0
EndIf
Return b1+b2+b3+b4
End Function
Function lePokeShort(bank,offset,short)
;because networkbytes are stored differently to x86 PC's (in network its little-endian)
;this function swaps byte 1 and byte 2 in an short and inserts it in the given bank
b1 = short And $ff
b2 = (short Shr 8) And $ff
PokeByte(bank,offset,b2)
PokeByte(bank,offset+1,b1)
End Function
Function lePeekShort(bank,offset)
;because networkbytes are stored differently to x86 PC's (in network its little-endian)
;this function read a short from a bank and swaps byte 1 and byte 2 then returns the new value
short = PeekShort(bank,offset)
b2 = (short And $ff) Shl 8
b1 = (short And $ff00) Shr 8
Return (b2 + b1)
End Function
Function Print(txt$)
AddTextAreaText(tarea,txt+Chr(10))
End Function
Function Write(txt$)
AddTextAreaText(tarea,txt)
End Function |
Comments
None.
Code Archives Forum