trancexx Posted August 16, 2008 Share Posted August 16, 2008 Being new to AutoIt, I feel rush with every new script I make, do you?Retrieving MX records for a specific domain is something that you will probably never need to do. Or would you?In case you would...There is few tools on the net that will do it for you, or you can use 'nslookup.exe' that ships with your windows. There is few scripts here on forum that is automating nslookup (chiefly unsuccessful scripts).But that is not what I was thinking.AutoIt is very powerful scripting language, and almost ideal for this kind of tasks.MX records are retrieved after doing so called MX look up (this is smart, right?), and that is done by sending query, request to some DNS server. This communication is done on port 53, binary protocol is used by sending and receiving UDP packages.It is very hard to find some documentation on this (written for average human being to understand). So, this script (what scrip?) is written mostly relying on RFC1034 and RFC1035.It will not check for online status so if you run it off line it will just take 10-15 sec of your precious time.Domain name should be in form of ...domain name lol (example.com). It is ease to 'upgrade' it to check for online status, or to query MX records for IP-adress, or to query for example SOA records or ANAME or...Main function is made of three (sub)functions, to keep thingh as transparent as possible. Each of them can be replaced with better ones. First one will connect to the DNS server, ask the question and provide us with answer, second one will extract interesting parts of that answer and last one will sort things up.Commented only the interesting parts.Script will not use any external program or whatever to get us MX records!Question was what script. Well, this one:expandcollapse popupOpt("MustDeclareVars", 1) Dim $domain = "autoit.com" ; change it to domain of your interest Dim $mx = MXRecords($domain) If IsArray($mx) Then Local $au For $j = 1 To $mx[0][0] $au &= $mx[0][$j] & " - " & $mx[1][$j] & @CRLF Next MsgBox(0, "MX records for " & $domain, $au) Else MsgBox(0, "MX records for " & $domain, "No Records") EndIf Func MXRecords($domain) Local $binary_data = MXQueryServer($domain) If $binary_data = -1 Then Return -1 Local $output = ExtractMXServerData($binary_data) SortArray($output) Return $output EndFunc ;==>MXRecords Func MXQueryServer($domain) Local $domain_array $domain_array = StringSplit($domain, ".", 1) Local $binarydom For $el = 1 To $domain_array[0] $binarydom &= Hex(BinaryLen($domain_array[$el]), 2) & StringTrimLeft(StringToBinary($domain_array[$el]), 2) Next $binarydom &= "00" ; for example, 'gmail.com' will be '05676D61696C03636F6D00' and 'autoit.com' will be '066175746F697403636F6D00' Local $identifier = Hex(Random(0, 1000, 1), 2) ; random hex number serving as a handle for the data that will be received Local $server_bin = "0x00" & $identifier & "01000001000000000000" & $binarydom & "000F0001" ; this is our query Local $num_time, $data For $num_time = 1 To 10 Local $query_server ; ten(10) DNS servers, we'll start with one that is our's default, if no response or local one switch to public free servers Switch $num_time Case 1 Local $loc_serv = StringSplit(RegRead("HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters", "DhcpNameServer"), " ", 1) If $loc_serv[0] > 0 Then If StringLeft($loc_serv[1], 3) <> "192" Then ; this kind of server is not what we want $query_server = $loc_serv[1] EndIf EndIf Case 2 $query_server = "4.2.2.1" Case 3 $query_server = "67.138.54.100" Case 4 $query_server = "208.67.222.222" Case 5 $query_server = "4.2.2.2" Case 6 $query_server = "4.2.2.3" Case 7 $query_server = "208.67.220.220" Case 8 $query_server = "4.2.2.4" Case 9 $query_server = "4.2.2.5" Case 10 $query_server = "4.2.2.6" Case 11 Return -1 EndSwitch If $query_server <> "" Then UDPStartup() Local $sock $sock = UDPOpen($query_server, 53) If $sock = -1 Then ; ok, that happens UDPCloseSocket($sock) UDPShutdown() ContinueLoop ; change server and try again EndIf UDPSend($sock, $server_bin) ; sending query Local $tik = 0 Do $data = UDPRecv($sock, 512) $tik += 1 Sleep(100) Until $data <> "" Or $tik = 8 ; waiting reasonable time for the response UDPShutdown() ; stopping service If $data <> "" And StringRight(BinaryMid($data, 2, 1), 2) = $identifier Then Return $data ; if there is data for us, return EndIf EndIf Next Return -1 EndFunc ;==>MXQueryServer Func ExtractMXServerData($binary_data) Local $num_answ = Dec(StringMid($binary_data, 15, 4)) ; representing number of answers provided by the server Local $arr = StringSplit($binary_data, "C00C000F0001", 1) ; splitting input; "C00C000F0001" - translated to human: "this is the answer for your MX query" If $num_answ <> $arr[0] - 1 Or $num_answ = 0 Then Return -1 ; dealing with possible options Local $pref[$arr[0]] ; preference number(s) Local $server[$arr[0]] ; server name(s) Local $output[2][$arr[0]] ; this goes out containing both server names and coresponding preference numbers $output[0][0] = $arr[0] - 1 Local $offset = 10 ; initial offset For $i = 2 To $arr[0] $arr[$i] = "0x" & $arr[$i] ; well, it is binary data $pref[$i - 1] = Dec(StringRight(BinaryMid($arr[$i], 7, 2), 4)) $offset += BinaryLen($arr[$i - 1]) + 6 ; adding lenght of every past part plus lenght of that "C00C000F0001" used for splitting Local $array = ReadBinary($binary_data, $offset) ; extraction of server names starts here While $array[1] = 192 ; dealing with special case $array = ReadBinary($binary_data, $array[6] + 2) WEnd $server[$i - 1] &= $array[2] & "." While $array[3] <> 0 ; the end will obviously be at $array[3] = 0 If $array[3] = 192 Then $array = ReadBinary($array[0], $array[4] + 2) If $array[3] = 0 Then $server[$i - 1] &= $array[2] ExitLoop Else $server[$i - 1] &= $array[2] & "." EndIf Else $array = ReadBinary($array[0], $array[5]) If $array[3] = 0 Then $server[$i - 1] &= $array[2] ExitLoop Else $server[$i - 1] &= $array[2] & "." EndIf EndIf WEnd $output[0][$i - 1] = $server[$i - 1] ; assigning $output[1][$i - 1] = $pref[$i - 1] ; part Next Return $output ; two-dimensional array EndFunc ;==>ExtractMXServerData Func ReadBinary($binary_data, $offset) Local $len = Dec(StringRight(BinaryMid($binary_data, $offset - 1, 1), 2)) Local $data_bin = BinaryMid($binary_data, $offset, $len) Local $checker = Dec(StringRight(BinaryMid($data_bin, 1, 1), 2)) Local $data = BinaryToString($data_bin) Local $triger = Dec(StringRight(BinaryMid($binary_data, $offset + $len, 1), 2)) Local $new_offset = Dec(StringRight(BinaryMid($binary_data, $offset + $len + 1, 1), 2)) Local $another_offset = $offset + $len + 1 Local $array[7] = [$binary_data, $len, $data, $triger, $new_offset, $another_offset, $checker] ; bit of this and bit of that Return $array EndFunc ;==>ReadBinary Func SortArray(ByRef $array) ; this will sort our $array by preferance numbers (in case of identical preferance, lower in order goes first - that's cool) If IsArray($array) Then ReDim $array[2][2 * $array[0][0] + 1] For $ij = $array[0][0] + 1 To 2 * $array[0][0] $array[1][$ij] = 1 Next For $bf = 1 To $array[0][0] For $cf = 1 To $array[0][0] If $array[1][$cf] - $array[1][$bf] > 0 Then $array[1][$cf + $array[0][0]] += 1 Next Next For $df = $array[0][0] + 1 To 2 * $array[0][0] For $ef = $array[0][0] + 1 To 2 * $array[0][0] If $ef = $df Then ContinueLoop If $array[1][$ef] - $array[1][$df] = 0 Then $array[1][$ef] += 1 Next Next Dim $aux_array[2][$array[0][0] + 1] $aux_array[0][0] = $array[0][0] For $ff = 1 To $array[0][0] $aux_array[1][$array[1][$ff + $array[0][0]]] = $array[1][$ff] $aux_array[0][$array[1][$ff + $array[0][0]]] = $array[0][$ff] Next $array = $aux_array Return $aux_array EndIf Return -1 EndFunc ;==>SortArrayPlease comment if you see any flaws. argumentum and Digisoul 2 ♡♡♡ . eMyvnE Link to comment Share on other sites More sharing options...
rudi Posted May 25, 2018 Share Posted May 25, 2018 Cool code! Thx!!! It' fine for all I need, but one question remains: Why do you "order" the found MX records in collumns, not rows? Just habit? At a first glance I've expected to be Col[0] = MX and Col[1] = Prio, e.g. Propably there is any benefit the way you've done it, and I miss it? Regards, Rudi. Earth is flat, pigs can fly, and Nuclear Power is SAFE! Link to comment Share on other sites More sharing options...
LWC Posted Saturday at 10:08 PM Share Posted Saturday at 10:08 PM (edited) On 5/25/2018 at 1:40 PM, rudi said: It' fine for all I need, but one question remains: Why do you "order" the found MX records in collumns, not rows? Just habit? At a first glance I've expected to be Col[0] = MX and Col[1] = Prio, e.g. I agree. It was probably also the reason a whole manual sort function was used instead of _ArraySort. So here's a revised version with: Automated sorting Detecting the router's address directly (with this) instead of relying on the registry A more direct detection of the first integer of the IPv4 address Deleted lots and lots of unneeded linebreaks Fixed spelling errors expandcollapse popup#include <Array.au3> Dim $domain = "gmail.com" ; change it to domain of your interest Dim $mx = MXRecords($domain) If IsArray($mx) Then _ArrayDisplay($mx) Else MsgBox(0, "MX records for " & $domain, "No Records") EndIf Func MXRecords($domain) Local $binary_data = MXQueryServer($domain) If $binary_data = -1 Then Return -1 Local $output = ExtractMXServerData($binary_data) _ArraySort($output, 0, 1, default, 1) Return $output EndFunc ;==>MXRecords Func MXQueryServer($domain) Local $domain_array $domain_array = StringSplit($domain, ".", 1) Local $binarydom For $el = 1 To $domain_array[0] $binarydom &= Hex(BinaryLen($domain_array[$el]), 2) & StringTrimLeft(StringToBinary($domain_array[$el]), 2) Next $binarydom &= "00" ; for example, 'gmail.com' will be '05676D61696C03636F6D00' and 'autoit.com' will be '066175746F697403636F6D00' Local $identifier = Hex(Random(0, 1000, 1), 2) ; random hex number serving as a handle for the data that will be received Local $server_bin = "0x00" & $identifier & "01000001000000000000" & $binarydom & "000F0001" ; this is our query Local $num_time, $data For $num_time = 1 To 10 Local $query_server ; ten(10) DNS servers, we'll start with one that is our's default, if no response or local one switch to public free servers Switch $num_time Case 1 Local $loc_serv = _GetGateway() If IsArray($loc_serv) Then if StringSplit($loc_serv[1], ".", 2)[0] <> "192" Then ; this kind of server is not what we want $query_server = $loc_serv[1] EndIf EndIf Case 2 $query_server = "4.2.2.1" Case 3 $query_server = "67.138.54.100" Case 4 $query_server = "208.67.222.222" Case 5 $query_server = "4.2.2.2" Case 6 $query_server = "4.2.2.3" Case 7 $query_server = "208.67.220.220" Case 8 $query_server = "4.2.2.4" Case 9 $query_server = "4.2.2.5" Case 10 $query_server = "4.2.2.6" Case 11 Return -1 EndSwitch If $query_server <> "" Then UDPStartup() Local $sock $sock = UDPOpen($query_server, 53) If $sock = -1 Then ; ok, that happens UDPCloseSocket($sock) UDPShutdown() ContinueLoop ; change server and try again EndIf UDPSend($sock, $server_bin) ; sending query Local $tik = 0 Do $data = UDPRecv($sock, 512) $tik += 1 Sleep(100) Until $data <> "" Or $tik = 8 ; waiting reasonable time for the response UDPShutdown() ; stopping service If $data <> "" And StringRight(BinaryMid($data, 2, 1), 2) = $identifier Then Return $data ; if there is data for us, return EndIf EndIf Next Return -1 EndFunc ;==>MXQueryServer Func ExtractMXServerData($binary_data) Local $num_answ = Dec(StringMid($binary_data, 15, 4)) ; representing number of answers provided by the server Local $arr = StringSplit($binary_data, "C00C000F0001", 1) ; splitting input; "C00C000F0001" - translated to human: "this is the answer for your MX query" If $num_answ <> $arr[0] - 1 Or $num_answ = 0 Then Return -1 ; dealing with possible options Local $pref[$arr[0]] ; preference number(s) Local $server[$arr[0]] ; server name(s) Local $output[1][2] ;[2][$arr[0]] ; this goes out containing both server names and coresponding preference numbers $output[0][0] = $arr[0] - 1 Local $offset = 10 ; initial offset For $i = 2 To $arr[0] $arr[$i] = "0x" & $arr[$i] ; well, it is binary data $pref[$i - 1] = Dec(StringRight(BinaryMid($arr[$i], 7, 2), 4)) $offset += BinaryLen($arr[$i - 1]) + 6 ; adding length of every past part plus length of that "C00C000F0001" used for splitting Local $array = ReadBinary($binary_data, $offset) ; extraction of server names starts here While $array[1] = 192 ; dealing with special case $array = ReadBinary($binary_data, $array[6] + 2) WEnd $server[$i - 1] &= $array[2] & "." While $array[3] <> 0 ; the end will obviously be at $array[3] = 0 If $array[3] = 192 Then $array = ReadBinary($array[0], $array[4] + 2) If $array[3] = 0 Then $server[$i - 1] &= $array[2] ExitLoop Else $server[$i - 1] &= $array[2] & "." EndIf Else $array = ReadBinary($array[0], $array[5]) If $array[3] = 0 Then $server[$i - 1] &= $array[2] ExitLoop Else $server[$i - 1] &= $array[2] & "." EndIf EndIf WEnd _ArrayAdd($output, $server[$i - 1]) $output[ubound($output)-1][1] = $pref[$i - 1] Next Return $output ; two-dimensional array EndFunc ;==>ExtractMXServerData Func ReadBinary($binary_data, $offset) Local $len = Dec(StringRight(BinaryMid($binary_data, $offset - 1, 1), 2)) Local $data_bin = BinaryMid($binary_data, $offset, $len) Local $checker = Dec(StringRight(BinaryMid($data_bin, 1, 1), 2)) Local $data = BinaryToString($data_bin) Local $triger = Dec(StringRight(BinaryMid($binary_data, $offset + $len, 1), 2)) Local $new_offset = Dec(StringRight(BinaryMid($binary_data, $offset + $len + 1, 1), 2)) Local $another_offset = $offset + $len + 1 Local $array[7] = [$binary_data, $len, $data, $triger, $new_offset, $another_offset, $checker] ; bit of this and bit of that Return $array EndFunc ;==>ReadBinary Func _GetGateway() ; Based on: ; Rajesh V R ; v 1.0 01 June 2009 ; use the adapter name as seen in the network connections dialog... Const $wbemFlagReturnImmediately = 0x10 Const $wbemFlagForwardOnly = 0x20 Local $colNICs="", $NIC, $strQuery, $objWMIService $strQuery = "SELECT * FROM Win32_NetworkAdapterConfiguration" $objWMIService = ObjGet("winmgmts:\\.\root\CIMV2") $colNICs = $objWMIService.ExecQuery($strQuery, "WQL", $wbemFlagReturnImmediately + $wbemFlagForwardOnly) Local $output[2] If IsObj($colNICs) Then For $NIC In $colNICs if isstring($NIC.DefaultIPGateway(0)) then $output[0] = $NIC.IPAddress(0) $output[1] = $NIC.DefaultIPGateway(0) ExitLoop endif Next Else Return SetError(-1, 0, "No WMI Objects Found for class: Win32_NetworkAdapterConfiguration") EndIf Return $output EndFunc Edited yesterday at 04:12 PM by LWC Added bullet point Link to comment Share on other sites More sharing options...
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now