Jump to content

Local Proxy Server


Recommended Posts

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.

Link to comment
Share on other sites

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?

Link to comment
Share on other sites

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

Link to comment
Share on other sites

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.

Link to comment
Share on other sites

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

Link to comment
Share on other sites

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

Link to comment
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
 Share

×
×
  • Create New...