TheBrainiac Posted November 7, 2013 Share Posted November 7, 2013 (edited) Greetings, I have been trying to code a DNS server in AutoIt. I have learned the protocol and I am about to complete the implementation. However, I have hit a road-block: AutoIt's internal UDP functions do not allow choosing a source port for an outgoing UDP packet. I'll illustrate the problem with this imaginary scenario where a Client with the IP 1.2.3.4 makes a query to the DNS Server 8.8.8.8: Client's query packet goes from 1.2.3.4:65432 to 8.8.8.8:53 Server's response goes from 8.8.8.8:53 to 1.2.3.4:65432. The problem with AutoIt's UDP functions is that to respond to the UDP Packet, I have to first create a UDP "Socket" using UDPOpen, which does not give me the option to keep 53 as the source port for the response packet. The scenario with my AutoIt server now looks like this: Client's query packet goes from 1.2.3.4:65432 to 8.8.8.8:53 Server opens a new UDP Socket to send data to the Client Server's response goes from 8.8.8.8:61234 to 1.2.3.4:65432. It seems that the devices I am using to make DNS requests to my server discard the response packet because of its strange source port. I have learned that the native functions are unable to solve my problem, so I'd like to know whether there are any workarounds for this. Thank you -Brainiac Edited November 9, 2013 by TheBrainiac Link to comment Share on other sites More sharing options...
lordofthestrings Posted November 7, 2013 Share Posted November 7, 2013 check udpbind() I would like to see the code when this is complete Kind regards Link to comment Share on other sites More sharing options...
TheBrainiac Posted November 7, 2013 Author Share Posted November 7, 2013 check udpbind() Unfortunately, UDPBind() can only be used to wait for incoming packets. As for the code, I'll just dump the (extremely crude) script I have right now. I'll clean it up a lot once it's functional. expandcollapse popup#include <ButtonConstants.au3> #include <EditConstants.au3> #include <GUIConstantsEx.au3> #include <StaticConstants.au3> #include <WindowsConstants.au3> Dim $dnslabels[10] Dim $dnsentries[10] Global $banned = ObjCreate("System.Collections.ArrayList") #Region ### START Koda GUI section ### Form=C:\Users\Dennis\Documents\dns.kxf $Form1 = GUICreate("DNS Visualizer", 266, 438, 192, 124) For $i = 0 To 9 $dnslabels[$i] = GUICtrlCreateLabel("", 8, 8 + 16 * $i, 252, 17) Next $Input1 = GUICtrlCreateInput("", 8, 200, 249, 21) $Button1 = GUICtrlCreateButton("Block", 8, 224, 75, 25) $Label3 = GUICtrlCreateLabel("Label3", 8, 256, 36, 17) $Label4 = GUICtrlCreateLabel("Label4", 8, 280, 36, 17) $Label5 = GUICtrlCreateLabel("Label5", 8, 304, 36, 17) $Button2 = GUICtrlCreateButton("Unblock", 182, 224, 75, 25) GUISetState(@SW_SHOW) #EndRegion ### END Koda GUI section ### GUIRegisterMsg($WM_COMMAND, "labelclick") OnAutoItExitRegister("Cleanup") UDPStartup() $socket = UDPBind(@IPAddress1, 53) If @error <> 0 Then Exit While 1 $packet = UDPRecv($socket, 512, 3) If $packet <> "" Then $data = $packet[0] ConsoleWrite($packet[1] & ":" & $packet[2] & @CRLF) visualize($data) $bdomain = BinaryMid($data, 13, BinaryLen($data) - 16) $sdomain = extractdomain($bdomain) ConsoleWrite("Extracted Domain Name: " & $sdomain & @CRLF) ConsoleWrite(@CRLF) If $banned.contains($sdomain) Then Dim $apacket[4] $apacket[0] = BinaryMid($data, 1, 2) $apacket[1] = "81800001000100000000" $apacket[2] = $bdomain $apacket[3] = "00010001C00C000100010000001C00045F735A8B" $rpacket = binarymerge($apacket) $sock = UDPOpen($packet[1], $packet[2]) UDPSend($sock, $rpacket) ConsoleWrite("->Sent deceiving packet" & @CRLF) entry_push("(" & $sdomain & ")") Else $abc = UDPOpen("8.8.8.8", 53) UDPSend($abc, $data) While 1 $dat = UDPRecv($abc, 512, 3) If $dat <> "" Then visualize($dat[0]) ConsoleWrite(@CRLF & $dat[1] & ":" & $dat[2] & @CRLF) ExitLoop EndIf Sleep(100) WEnd $sock = UDPOpen($packet[1], $packet[2]) If @error Then MsgBox(16, "", "ARGON") ConsoleWrite(IsBinary($dat) & @CRLF) UDPSend($sock, $dat[0]) UDPCloseSocket($abc) entry_push($sdomain) EndIf EndIf $data = "" Sleep(100) WEnd Func visualize($binary) $tab0 = "" $tab1 = "" ConsoleWrite("Len: " & BinaryLen($binary) & @CRLF) For $i = 1 To BinaryLen($binary) $tab0 &= Hex(BinaryMid($binary, $i, 1), 2) & " " $symbol = BinaryToString(BinaryMid($binary, $i, 1)) If StringInStr("abcdefghijklmnopqrstuvwxyz0123456789.-", $symbol) Then $tab1 &= $symbol & " " Else $tab1 &= "? " EndIf If Mod($i, 8) = 0 Then ConsoleWrite($tab0 & @TAB & $tab1 & @CRLF) $tab0 = "" $tab1 = "" EndIf Next If Mod($i, 8) <> 0 Then ConsoleWrite($tab0) For $j = 0 To 8 - Mod($i, 8) ConsoleWrite(" ") Next ConsoleWrite(@TAB & $tab1) EndIf ConsoleWrite(@CRLF) EndFunc ;==>visualize Func Cleanup() UDPCloseSocket($socket) UDPShutdown() EndFunc ;==>Cleanup Func extractdomain($binary) $domain = "" For $k = 2 To BinaryLen($binary) - 1 $symbol = BinaryToString(BinaryMid($binary, $k, 1)) If StringInStr("abcdefghijklmnopqrstuvwxyz0123456789.-", $symbol) Then $domain &= $symbol Else $domain &= "." EndIf Next Return $domain EndFunc ;==>extractdomain Func entry_push($entry) For $i = 0 To 8 $dnsentries[$i] = $dnsentries[$i + 1] GUICtrlSetData($dnslabels[$i], $dnsentries[$i]) Next $dnsentries[9] = $entry GUICtrlSetData($dnslabels[9], $entry) EndFunc ;==>entry_push Func labelclick($hwnd, $nmsg, $wparam, $lparam) For $i = 0 To 9 If $wparam = $dnslabels[$i] Then GUICtrlSetData($Input1, $dnsentries[$i]) Next If $wparam = $Button1 Then $banned.add(GUICtrlRead($Input1)) If $wparam = $Button2 Then $banned.remove(StringTrimLeft(StringTrimRight(GUICtrlRead($Input1), 1), 1)) EndFunc ;==>labelclick Func binarymerge($aBinary) Local $struct, $struct2 $ptr = 0 $len = 0 For $i = 0 To UBound($aBinary) - 1 $len += BinaryLen($aBinary[$i]) Next $struct = DllStructCreate("byte[" & $len & "]") For $i = 0 To UBound($aBinary) - 1 $struct2 = DllStructCreate("byte[" & BinaryLen($aBinary[$i]) & "]", DllStructGetPtr($struct) + $ptr) DllStructSetData($struct2, 1, $aBinary[$i]) $ptr += BinaryLen($aBinary[$i]) $struct2 = 0 Next $binary = DllStructGetData($struct, 1) $struct = 0 Return $binary EndFunc It contains a few goodies, such as a function that merges arrays of binary data into one variable and an Object that implements functions of an ArrayList. The attentive observer will notice that the aim of this project is to sniff DNS requests from mobile devices in order to detect and block potentially unwanted background traffic and ads. The user can block and unblock domains at runtime (blocked domains point to 127.0.0.1). Everything works except the UDP connections. Link to comment Share on other sites More sharing options...
Gianni Posted November 7, 2013 Share Posted November 7, 2013 Hi theBrainiac have a look to this >UDF, maybe it can interest you, Anyway, I tried to use it to resolve IP addresses in hostname without success can someone test that UDF to see if it works with you? p.s. The UDPOpen() function has the "port" parameter to specify the port on which the created socket will be connected. What's wrong with it? Chimp small minds discuss people average minds discuss events great minds discuss ideas.... and use AutoIt.... Link to comment Share on other sites More sharing options...
TheBrainiac Posted November 7, 2013 Author Share Posted November 7, 2013 Thank you, I will have a look at that! It seems the program does kind of what I'm doing, except it translates the data back and forth between two different protocols. The UDPOpen() function has the "port" parameter to specify the port on which the created socket will be connected. What you are specifying in UDPOpen() is the remote port, that is the port where the packet is going to. What I have to set is the local port, which is the one where my packet comes from. UDPOpen() chooses a random port for that. I suppose there isn't a way to build IP packets in Windows, is there? I mean that would be bad news for the internet. Link to comment Share on other sites More sharing options...
lordofthestrings Posted November 8, 2013 Share Posted November 8, 2013 (edited) to reverse lookup you need to query the pointer record in the in-addr.arpa domain like this: (note the reversed IP address) D:\>nslookup Default Server: UnKnown Address: 1xx.23x.116.158 > set q=ptr > 61.164.198.64.in-addr.arpa Server: UnKnown Address: 1xx.23x.116.158 Non-authoritative answer: 61.164.198.64.in-addr.arpa name = 64-198-164-61.ip.mcleodusa.net > Edited November 8, 2013 by lordofthestrings Link to comment Share on other sites More sharing options...
TheBrainiac Posted November 8, 2013 Author Share Posted November 8, 2013 (edited) Reverse DNS lookups aren't my problem, although I didn't know that and it might come in handy down the road.. It also explains what my phone has been doing with all the in-arpa queries. Edit: I'm being an egocentric whackjob, nevermind Anyway, is there no UDF or exotic DLL that lets me tweak a UDP socket handle's source port? I mean this is a frequently used feature of the UDP protocol, there's got to be something for Windows. Edited November 9, 2013 by TheBrainiac Link to comment Share on other sites More sharing options...
Gianni Posted November 9, 2013 Share Posted November 9, 2013 (edited) I think the DNS lookups answer was related to my question in post #4, (thanks lordofthestrings) TheBrainiac, a question, isn't the 'port' parameter in UDPBind() the port where you wait for udp data sent by the sender? sorry, you already say about this in post #3 Edited November 9, 2013 by PincoPanco Chimp small minds discuss people average minds discuss events great minds discuss ideas.... and use AutoIt.... Link to comment Share on other sites More sharing options...
TheBrainiac Posted November 9, 2013 Author Share Posted November 9, 2013 I've found out about Ws2_32.dll and I'm examining its functions now. If I get it to work (never used DllCall outside of copy-pasting code) I'll post my results. Link to comment Share on other sites More sharing options...
BrewManNH Posted November 9, 2013 Share Posted November 9, 2013 Wouldn't it be easier to just create a VM with Server 2003/2008 or some version of Linux and use that as your DNS server? If I posted any code, assume that code was written using the latest release version unless stated otherwise. Also, if it doesn't work on XP I can't help with that because I don't have access to XP, and I'm not going to.Give a programmer the correct code and he can do his work for a day. Teach a programmer to debug and he can do his work for a lifetime - by Chirag GudeHow to ask questions the smart way! I hereby grant any person the right to use any code I post, that I am the original author of, on the autoitscript.com forums, unless I've specifically stated otherwise in the code or the thread post. If you do use my code all I ask, as a courtesy, is to make note of where you got it from. Back up and restore Windows user files _Array.au3 - Modified array functions that include support for 2D arrays. - ColorChooser - An add-on for SciTE that pops up a color dialog so you can select and paste a color code into a script. - Customizable Splashscreen GUI w/Progress Bar - Create a custom "splash screen" GUI with a progress bar and custom label. - _FileGetProperty - Retrieve the properties of a file - SciTE Toolbar - A toolbar demo for use with the SciTE editor - GUIRegisterMsg demo - Demo script to show how to use the Windows messages to interact with controls and your GUI. - Latin Square password generator Link to comment Share on other sites More sharing options...
Solution TheBrainiac Posted November 9, 2013 Author Solution Share Posted November 9, 2013 (edited) Okay, I made it. I used Ws2_32.dll's functions. Here is my code: expandcollapse popupUDPStartup() $hWs2_32 = DllOpen("ws2_32.dll") $hSocket = _WinsockCreateSocket(2, 2, 17) _WinsockBind($hSocket, "192.168.178.20", 53); The source address and port for the Socket. The IP must be your LAN IP. I've found that 127.0.0.1 does not work. _WinsockConnect($hSocket, "192.168.178.22", 65432); The destination IP and port. _WinsockSend($hSocket, "This UDP Packet came from Port 53!") Func _WinsockCreateSocket($Address_Family, $Socket_Type, $Protocol) $iRet = DllCall($hWs2_32, "int", "socket", "int", $Address_Family, "int", $Socket_Type, "int", $Protocol) Return $iRet[0] EndFunc Func _WinsockBind($hSocket, $IP, $Port) $hAddr = _SocketAddr($IP, $Port) $iRet = DllCall($hWs2_32, "int", "bind", "uint", $hSocket, "ptr", DllStructGetPtr($hAddr), "int", DllStructGetSize($hAddr)) Return $iRet[0] EndFunc Func _WinsockConnect($hSocket, $IP, $Port) $hAddr = _SocketAddr($IP, $Port) $iRet = DllCall($hWs2_32, "int", "connect", "uint", $hSocket, "ptr", DllStructGetPtr($hAddr), "int", DllStructGetSize($hAddr)) EndFunc Func _WinsockSend($hSocket, $data) $hBuf = DllStructCreate("byte[" & BinaryLen($data) & "]") DllStructSetData($hBuf, 1, $data) $iRet = DllCall($hWs2_32, "int", "send", "uint", $hSocket, "ptr", DllStructGetPtr($hBuf), "int", DllStructGetSize($hBuf), "int", 0) EndFunc Func _SocketAddr($IP, $Port, $Address_Family = 2) $stAddress = DllStructCreate("short; ushort; uint; char[8]") DllStructSetData($stAddress, 1, $Address_Family) $iRet = DllCall($hWs2_32, "ushort", "htons", "ushort", $Port) DllStructSetData($stAddress, 2, $iRet[0]) $iRet = DllCall($hWs2_32, "uint", "inet_addr", "str", $IP) DllStructSetData($stAddress, 3, $iRet[0]) Return $stAddress EndFunc ;==>_SocketAddr Func _WSAGetLastError() $iRet = DllCall($hWs2_32, "int", "WSAGetLastError") Return $iRet[0] EndFunc ;==>_WSAGetLastError On the other computer, there was an AutoIt UDP listener running. It said the source port of the packet received is indeed 53. There is PLENTY of room to expand this and make it into an excellent UDF. I only implemented the functions I need for now, but you probably see where to expand this. Here's the list of functions that could potentially be adapted in the UDF: http://msdn.microsoft.com/en-us/library/windows/desktop/ms741394(v=vs.85).aspx Edited November 9, 2013 by TheBrainiac lordofthestrings 1 Link to comment Share on other sites More sharing options...
f1iqf Posted December 4, 2013 Share Posted December 4, 2013 (edited) I adapted TheBrainiac code to provide a simple way to make a real udp server. See example below. The example is just echoing to any udp request. Cheers, Nicolas expandcollapse popupUDPStartup() Local $socket = UDPBind(@IPAddress1, 53) If @error <> 0 Then Exit While 1 Local $data = UDPRecv($socket, 1024, 2) If IsArray($data) Then _UDPSendto($socket, $data[0], $data[1], $data[2]) ; answer the same packet to the client... EndIf Sleep(100) WEnd ; Send a udp packet to a specific address originating from an existing socket ; parameters : $udpsocket : socket (as returned by UDBbind) ; $data : binary to send ; $IP : destination IP ; $Port : destination Port ; $allowbroadcast : If True, allow sending broadcasts ; ; Returns : number of bytes sent, or check @Error if <0 Func _UDPSendto($udpsocket, $data, $IP, $Port, $allowbroadcast=False) If Not IsDeclared("Dll_Ws2_32") Then ; If not already declared, open Dll ws2_32.dll and set up auto close at program exit Global $Dll_Ws2_32=DllOpen("ws2_32.dll") If $Dll_Ws2_32=-1 Then SetError(10101) return -1 EndIf OnAutoItExitRegister("_Close_ws2_32") EndIf If $allowbroadcast Then Local $char = DllStructCreate("char") DllStructSetData($char, 1, 1) DllCall($Dll_Ws2_32, "int", "setsockopt", "uint", $udpsocket[1], "int", 0xffff, "int", 0x0020, "ptr", DllStructGetPtr($char), "int", 1) EndIf ; create and populate a sockaddr struct from $IP and $Port Local $stAddress = DllStructCreate("short; ushort; uint; char[8]") DllStructSetData($stAddress, 1, 2) Local $iRet = DllCall($Dll_Ws2_32, "ushort", "htons", "ushort", $Port) If Not IsArray($iRet) Then return -1 DllStructSetData($stAddress, 2, $iRet[0]) If Not IsArray($iRet) Then return -1 $iRet = DllCall($Dll_Ws2_32, "uint", "inet_addr", "str", $IP) DllStructSetData($stAddress, 3, $iRet[0]) ; Create buffer with data Local $hBuf = DllStructCreate("byte[" & BinaryLen($data) & "]") DllStructSetData($hBuf, 1, $data) ; Send packet $iRet = DllCall($Dll_Ws2_32, "int", "sendto", "uint", $udpsocket[1], "ptr", DllStructGetPtr($hBuf), "int", DllStructGetSize($hBuf), "int", 0, "ptr", DllStructGetPtr($stAddress), "int", DllStructGetSize($stAddress)) If Not IsArray($iRet) Then return -1 ; check for error If $iRet[0]<0 Then ; Set @error with last error from WSAGetLastError Local $errno = DllCall($Dll_Ws2_32, "int", "WSAGetLastError") SetError($errno[0]) EndIf return $iRet[0] EndFunc Func _Close_ws2_32() DllClose($Dll_Ws2_32) EndFunc Edited December 4, 2013 by f1iqf 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