Jump to content
Sign in to follow this  
Shanheavel

Local Proxy Server

Recommended Posts

Shanheavel

Hi,

I'm trying all day to write a working proxy server, but it still doesn't work correctly. I'm not good at network functions, so maybe I've forgot about something.

It should receive, modify and send data between a browser and web server.

Here is a code. I just added a short comments. I hope it will make the script more readably.

#Region Tables
#include <Array.au3>

Global $sProxyIP = @IPAddress1, $iProxyPort = 8080, $iProxySocket = -1
Global $iNewSocket, $asLines[0], $sHost, $iLen
Global $aiBrowserSocket[0], $asBrowserRecv[0], $aiServerSocket[0], $asServerRecv[0], $aiServerContentLen[0]

#EndRegion Tables

#Region Initialization
If Not TCPStartup() Then Exit @ScriptLineNumber
$iProxySocket = TCPListen($sProxyIP, $iProxyPort)
If @error Then Exit @ScriptLineNumber
#EndRegion Initialization

While 1
    ;Accepting new sockets
    $iNewSocket = TCPAccept($iProxySocket)
    If $iNewSocket >= 0 Then ProxyAddArray($iNewSocket)

    ;Browser --> Proxy
    For $socket = 0 To UBound($asBrowserRecv) - 1
        $asBrowserRecv[$socket] = BinaryToString(TCPRecv($aiBrowserSocket[$socket], 1024 ^ 2))
        If @error Then
            ProxyDeleteArray($socket)
            $socket += 1
            ContinueLoop
        EndIf
    Next

    ;Browser data analyzing
    For $socket = 0 To UBound($asBrowserRecv) - 1
        $sHost = ''
        $asLines = StringSplit($asBrowserRecv[$socket], @CRLF, 1)
        For $line = 1 To $asLines[0]
            If StringLeft($asLines[$line], 4) = 'Host' Then
                $sHost = StringTrimLeft($asLines[$line], 6)
                ExitLoop
            EndIf
        Next
        $aiServerSocket[$socket] = TCPConnect(TCPNameToIP($sHost), 80)
        If @error Then
            ProxyDeleteArray($socket)
            $socket += 1
            ContinueLoop
        EndIf
    Next

    ;Proxy --> Web Page
    For $socket = 0 To UBound($aiServerSocket) - 1
        If $aiServerSocket[$socket] < 0 Then ContinueLoop
        $asServerRecv[$socket] = TCPSend($aiServerSocket[$socket], $asBrowserRecv[$socket])
        If @error Then $aiServerSocket[$socket] = -1
    Next

    ;Web Page --> Proxy
    For $socket = 0 To UBound($aiServerSocket) - 1
        If $aiServerSocket[$socket] < 0 Then ContinueLoop
        $iLen = 0
        $asServerRecv[$socket] = BinaryToString(TCPRecv($aiServerSocket[$socket], 1024 ^ 2 * 10))
        If StringLen($asServerRecv[$socket]) = 0 Then ContinueLoop
        $asLines = StringSplit($asServerRecv[$socket], @CRLF, 1)
        If @error Then $aiServerSocket[$socket] = -1
        For $line = 1 To $asLines[0]
            ;Data lenght
            If StringLeft($asLines[$line], 14) = 'Content-Length' Then
                $iLen = StringTrimLeft($asLines[$line], 16)
                $aiServerContentLen[$socket] = $iLen
                ExitLoop
            EndIf
        Next
    Next

    ;Proxy --> Browser
    For $socket = 0 To UBound($aiBrowserSocket) - 1
        If $aiServerContentLen[$socket] > StringLen($asBrowserRecv[$socket]) Then ContinueLoop
        TCPSend($aiBrowserSocket[$socket], $asServerRecv[$socket])
    Next
WEnd

#Region Proxy
Func ProxyAddArray($iSocket)
    _ArrayAdd($aiBrowserSocket, $iSocket)
    _ArrayAdd($asBrowserRecv, '')
    _ArrayAdd($aiServerSocket, -1)
    _ArrayAdd($asServerRecv, '')
    _ArrayAdd($aiServerContentLen, 0)
EndFunc   ;==>ProxyAddArray

Func ProxyDeleteArray($iIndex)
    _ArrayAdd($aiBrowserSocket, $iIndex)
    _ArrayAdd($asBrowserRecv, $iIndex)
    _ArrayAdd($aiServerSocket, $iIndex)
    _ArrayAdd($asServerRecv, $iIndex)
    _ArrayAdd($aiServerContentLen, $iIndex)
EndFunc   ;==>ProxyDeleteArray
#EndRegion Proxy

Important:

Before you will check this, you should change connection setting in your web browser.

And please do not post links to other old proxy server from Autoit Forums. I've tried them all.

Share this post


Link to post
Share on other sites
Shanheavel

I see that no one is able to help me. So I wrote a new version of my proxy server. It does not use arrays. I think it is much simpler. However it still has problem with loading most sites. 

#Region Tables
Global $sProxyIP = @IPAddress1, $iProxyPort = 8080, $iProxySocket = -1
Global $iBrowserSocket, $sBrowserRecv
Global $iServerSocket, $sServerRecv, $iContentLenght

#EndRegion Tables

#Region Initialization
If Not TCPStartup() Then Exit @ScriptLineNumber
$iProxySocket = TCPListen($sProxyIP, $iProxyPort)
If @error Then Exit @ScriptLineNumber
#EndRegion Initialization

While 1
    Do
        $iBrowserSocket = TCPAccept($iProxySocket)
        Sleep(10)
    Until $iBrowserSocket > -1

    For $i = 1 To 100
        $sBrowserRecv = TCPRecv($iBrowserSocket, 1024 ^ 2)
        If $sBrowserRecv Then ExitLoop
        Sleep(10)
    Next

    If $sBrowserRecv Then
        If HTTPRequest() Then TCPSend($iBrowserSocket, $sServerRecv)
    EndIf
    TCPCloseSocket($iBrowserSocket)
WEnd

Func HTTPRequest()
    Local $asLines = StringSplit($sBrowserRecv, @CRLF, 1), $asLineParts[0]
    $iContentLenght = 0
    For $line = 1 To $asLines[0]
        $asLineParts = StringSplit($asLines[$line], ': ', 1)
        If $asLineParts[0] < 2 Then ContinueLoop
        Assign('Browser ' & $asLineParts[1], $asLineParts[2])
    Next
    $iServerSocket = TCPConnect(TCPNameToIP(Eval('Browser Host')), 80)
    If $iServerSocket < 0 Then Return
    If TCPSend($iServerSocket, $sBrowserRecv) <> StringLen($sBrowserRecv) Then Exit 2
    $sServerRecv = TCPRecv($iServerSocket, 1024 ^ 2)
    If @error Then Return
    $sServerRecv = BinaryToString($sServerRecv, 1)
    $asLines = StringSplit($sServerRecv, @CRLF, 1)
    For $line = 1 To $asLines[0]
        $asLineParts = StringSplit($asLines[$line], ': ', 1)
        If $asLineParts[0] < 2 Then ContinueLoop
        Switch $asLineParts[1]
            Case 'Content-Length'
                $iContentLenght = $asLineParts[2]
        EndSwitch
    Next
    For $i = 1 To 100
        If StringLen($sServerRecv) >= $iContentLenght Then ExitLoop
        $sServerRecv &= BinaryToString(TCPRecv($iServerSocket, 1024 ^ 2), 1)
        Sleep(10)
    Next
    If StringLen($sServerRecv) < $iContentLenght Then
        MsgBox(32, StringLen($sServerRecv) & '/' & $iContentLenght, $sServerRecv)
    EndIf
    Return 1
EndFunc   ;==>HTTPRequest

For example, it loads wikipedia.org only partly. 

Have you any idea, how to fix this?

Share this post


Link to post
Share on other sites
ripdad

Your script has an array error at this line:

Func HTTPRequest()
    Local $asLines = StringSplit($sBrowserRecv, @CRLF, 1), $asLineParts[0]; <======

I know you said:

And please do not post links to other old proxy server from Autoit Forums. I've tried them all.

 

I'm not sure what you tried -- It's not perfect, but, did you try this?

'?do=embed' frameborder='0' data-embedContent>>

At the very least, you could get some ideas from it.


"The mediocre teacher tells. The Good teacher explains. The superior teacher demonstrates. The great teacher inspires." -William Arthur Ward

Share this post


Link to post
Share on other sites
Shanheavel

Your script has an array error at this line:

Func HTTPRequest()
    Local $asLines = StringSplit($sBrowserRecv, @CRLF, 1), $asLineParts[0]; <======

It is hard to get an array error with StringSplit function, so I think  $asLineParts[0] is a problem for you. You probably have a older AutoIt version, where assigning empty arrays was not allowed. Just delete "[0]" at this point. 

And yes, I tried this. I have to admit that my code was inspired by yours. I want to write something like you, but much simpler.

Share this post


Link to post
Share on other sites
ripdad

Yes, I used an older version of AutoIt -- It slipped my mind about that new feature.

You could strip my existing code to bare minimum. It wouldn't have any features though.

In any case, I try not to add any more code than what is necessary to make it work with

acceptable accuracy. It was a very slow process to make it that way. A lot of "trial and error".

Also at this time, it's not a good idea to check for an error after TCPRecv, if you're using a

newer version of AutoIt. A bug exist where it will exit the loop before you have received data.

I assume it will get fixed in some future update.

Ticket link: http://www.autoitscript.com/trac/autoit/ticket/2596

You'll find a work-around for it in my code, where I used several time-out schemes.

The For Loop, 1 to 100 is one of them.


"The mediocre teacher tells. The Good teacher explains. The superior teacher demonstrates. The great teacher inspires." -William Arthur Ward

Share this post


Link to post
Share on other sites
ripdad

I ran some test with this arrangement today...

; Example Section Only
;
;===============================================
For $i = 1 To 100
    $recv = TCPRecv($socket, 10240, 1)
    If @error And _WSA_GetLastError() Then; <- both conditions must exist to exitloop
        ExitLoop
    EndIf
    ;
    If StringLeft($recv, 2) = '0x' Then
        $string &= BinaryToString($recv)
    EndIf
    ;
    Sleep(10)
Next
;===============================================
;
Func _WSA_GetLastError()
    Local $array = DllCall('ws2_32.dll', 'int', 'WSAGetLastError')
    If @error Then Return -1
    Return $array[0]
EndFunc
;

If $recv is blank with an @error of -1 (meaning, it has not received data yet)
and _WSA_GetLastError() is 0, then it will continue to loop. Otherwise, when
both @error and _WSA_GetLastError() exist, it will then exit the loop.

So far, This seems to work well.

If it does okay over the next week, I'll update my code.


"The mediocre teacher tells. The Good teacher explains. The superior teacher demonstrates. The great teacher inspires." -William Arthur Ward

Share this post


Link to post
Share on other sites

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 account

Sign in

Already have an account? Sign in here.

Sign In Now
Sign in to follow this  

  • Similar Content

    • Spartan117
      By Spartan117
      Hi everyone,
      I wonder if there is a cloud service that can offer a physical server so that AutoIT can turn as it is in a physical machine.
      Thank you
    • simy8891
      By simy8891
      Hi guys,
      It's been a while since I wrote my last message here and a while since I used AutoIt. I'm currently sort of desperate and I'm trying to find some help in regards of getting the network usage per process!
      I'm not interested in the total network usage of the NIC, but only on a specific PID's network utilization. They idea is to collect the amount of traffic uploaded and downloaded by a list of specific processes. So far Process Hacker and Process Explorer are capable of getting what I need, but I need to use these numbers in another script so they're sort of useless to me. I can't seem to find a way around it.
      Any idea, help is greatly appreciated.
      Thanks
    • ripdad
      By ripdad
      I have had several people ask for this, so I decided to work the algorithm for it and this is the result.
      What is it?
      A Gateway Proxy Sends and Receives Data Unmodified.
      https://en.wikipedia.org/wiki/Proxy_server
      What is it used for?
      You can use it as a gateway, relay or router between two known static IP addresses.
      More information is in the header of the script.
      Download: LocalGatewayProxy.au3
      You will need WSA_NBTCP.au3 from here:
      https://www.autoitscript.com/forum/topic/191954-wsa_nbtcp-v100-udf/
      If you have any questions or problems, let me know.
       
    • ripdad
      By ripdad

      This script is based on algorithm code from EnrMa.
      Updated: January 22, 2018
      Made improvements. Changes are in the script header.
      Known Issues: AutoIt x64 does not work properly with this script.
      Download: LocalProxyServer_v1.00.zip
       
×