http, SOCKS4,5 - Proxy-Connection

Share your advanced PureBasic knowledge/code with the community.
User avatar
HeX0R
Addict
Addict
Posts: 1189
Joined: Mon Sep 20, 2004 7:12 am
Location: Hell

http, SOCKS4,5 - Proxy-Connection

Post by HeX0R »

The user / pass - authorization is untested, cause it's really difficult to find such proxys ;)

Code: Select all

;+----------------------------------+
; Proxy_Connect
;
; (c)HeX0R 2004
;
; Procedure for giving your online-applications the
; possibility to connect through different proxys
; like http, socks4 and socks5.
;
; NOT meant for connecting to websites!
; For this check Num3's example here:
; http://jconserv.net/purebasic/viewtopic.php?t=10327
;
;+----------------------------------+

InitNetwork()

Procedure.l IsIP( ip.s )
  ;ReturnValues :
  ;0 = no ip
  ;1 = IPv4 - IP
  ;2 = IPv6 - IP
  count.l = CountString(ip, ".")
  If count = 3
    ret.l = 1
  ElseIf count = 5
    ret.l = 2
  Else
    ProcedureReturn 0
  EndIf
  For i = 0 To count
    a$ = StringField(ip, i + 1, ".")
    If a$ = "" Or Str(Val(a$)) <> a$ Or Val(a$) > 255 Or Val(a$) < 0
      ProcedureReturn 0
    EndIf
  Next i
  ProcedureReturn ret
EndProcedure

Procedure.l Proxy_Connect( proxy_ip.s, proxy_port.l, ip_to_connect.s, port_to_connect.l, type.l, username.s, userpass.s, timeout.l )
  ;proxy_ip        = IP or URL of the Proxy-Server
  ;proxy_port      = Port of the Proxy-Server
  ;ip_to_connect   = IP or URL of where you want to connect through proxy. ATTENTION:
  ;  SOCKS4 only supports IP in IPv4-format! You have to get the IP first before using this on urls, otherwise it will fail!
  ;port_to_connect = Port of where you want to connect through proxy
  ;type            = 0 -> http-proxy
  ;type            = 1 -> socks4-proxy
  ;type            = 2 -> socks5-proxy
  ;If no authorization is needed set username and userpass = ""
  ;timeout         -> Time after connection-trial will time out (in SECONDS)
  ;Return-Value    = 0 -> error ; Return-Value > 0 -> ConnectionID
  
  *buffer = AllocateMemory(1024)
  If *buffer = 0
    ProcedureReturn #False
  EndIf
  
  netid.l = OpenNetworkConnection(proxy_ip, proxy_port)
  
  If netid = 0
    FreeMemory(*buffer)
    ProcedureReturn #False
  EndIf

  Select type
  
    Case 0
      ;====================
      ;-HTTP - Proxy
      ;====================
      ;Based on Num3's http-proxy-snippet , THX! ->
      ;http://jconserv.net/purebasic/viewtopic.php?t=10327
      
      text$ = "CONNECT " + ip_to_connect + ":" + Str(port_to_connect) + " HTTP/1.0" + #CRLF$
      
      If username And userpass
        user$ = username + ":" + userpass
        length.l = Len(user$) * 2
        If length < 64
          length = 64
        EndIf
        Base64Encoder(@user$, Len(user$), *buffer, length)
        encoded$ = PeekS(*buffer)
        text$ + "Authorization: Basic " + encoded$ + #CRLF$
        text$ + "Proxy-Authorization: Basic " + encoded$ + #CRLF$
      EndIf
      text$ + #CRLF$
 
      SendNetworkData(netid, @text$, Len(text$))
      check_timeout.l = ElapsedMilliseconds() + ( timeout * 1000 )
      Repeat
        Delay(10)
        If NetworkClientEvent(netid) = 2
          Content$ = Space(14500)
          length.l = ReceiveNetworkData(netid, @Content$, 14500)
          While length = 14500
            ;Clear Input-Buffer
            length = ReceiveNetworkData(netid, *buffer, 14500)
          Wend
          Break
        EndIf
      Until check_timeout < ElapsedMilliseconds()
      Result.l = 0
      For i = 1 To CountString(Content$, Chr(10))
        a$ = Trim(StringField(Content$, i, Chr(10)))
        If Left(a$, 7) = "HTTP/1."
          Result = Val(StringField(Content$, 2, Chr(32)))
          Break
        EndIf
      Next i
      If check_timeout < ElapsedMilliseconds() Or Result <> 200
        FreeMemory(*buffer)
        CloseNetworkConnection(netid)
        ProcedureReturn #False
      EndIf
      FreeMemory(*buffer)
      ProcedureReturn netid

    Case 1
      ;====================
      ;-Socks4 - Proxy
      ;====================
      
      ;Socks4 only supports IPv4 !
      ;You have to do a DNS-Lookup before using this on urls, otherwise it will fail!
      If IsIP(ip_to_connect) <> 1
        FreeMemory(*buffer)
        CloseNetworkConnection(netid)
        ProcedureReturn #False
      EndIf
      ;-Phase 1 SOCK4
      ;Send Request
      PokeB(*buffer, 4)
      PokeB(*buffer + 1, 1)
      hi.l = Int(port_to_connect / 256)
      lo.l = port_to_connect - (256 * hi)
      PokeB(*buffer + 2, hi)
      PokeB(*buffer + 3, lo)
      For i = 1 To 4
        PokeB(*buffer + 3 + i, Val(StringField(ip_to_connect, i, ".")) & 255)
      Next i
      PokeS(*buffer + 8, username)
      length.l = 9 + Len(username)
      SendNetworkData(netid, *buffer, length)
      ;Check if connection is established
      check_timeout.l = ElapsedMilliseconds() + ( timeout * 1000 )
      Repeat
        Delay(10)
        If NetworkClientEvent(netid) = 2
          ReceiveNetworkData(netid, *buffer, 1024)
          ver.l = PeekB(*buffer) & 255
          CD.l = PeekB(*buffer + 1) & 255
          port.l = (PeekB(*buffer + 2) & 255) * 256
          port + (PeekB(*buffer + 3) & 255)
          ip.s = Str(PeekB(*buffer + 4) & 255) + "." + Str(PeekB(*buffer + 5) & 255) + "."
          ip + Str(PeekB(*buffer + 6) & 255) + "." + Str(PeekB(*buffer + 7) & 255)
          Break
        EndIf
      Until check_timeout < ElapsedMilliseconds()
      If check_timeout < ElapsedMilliseconds() Or ver <> 0 Or CD <> 90
        FreeMemory(*buffer)
        CloseNetworkConnection(netid)
        ProcedureReturn #False
      EndIf
      ;IP and Port should be the same like ip_to_connect/port_to_connect and is just for information
      Debug "Connected to IP:" + ip
      Debug "Connected to Port:" + Str(port)
      FreeMemory(*buffer)
      ProcedureReturn netid
      
    Case 2
      ;====================
      ;-Socks5 - Proxy
      ;====================

      ;-Phase 1 SOCK5
      ;Send wished method
      If username = "" And userpass = ""
        length.l = 3
        PokeB(*buffer, 5)
        PokeB(*buffer + 1, 1)
        PokeB(*buffer + 2, 0)
      Else
        length.l = 4
        PokeB(*buffer, 5)
        PokeB(*buffer + 1, 2)
        PokeB(*buffer + 2, 0)
        PokeB(*buffer + 3, 2) 
      EndIf
      SendNetworkData(netid, *buffer, length)
      ;Check if method is allowed
      check_timeout.l = ElapsedMilliseconds() + ( timeout * 1000 )
      Repeat
        Delay(10)
        If NetworkClientEvent(netid) = 2
          ReceiveNetworkData(netid, *buffer, 2)
          ver.l = PeekB(*buffer) & 255
          method.l = PeekB(*buffer + 1) & 255
          Break
        EndIf
      Until check_timeout < ElapsedMilliseconds()
      If check_timeout < ElapsedMilliseconds() Or ver <> 5 Or method = 255
        FreeMemory(*buffer)
        CloseNetworkConnection(netid)
        ProcedureReturn #False
      EndIf
      If method = 2
        ;-Phase 2 SOCK5
        ;Send Username/Password (if allowed)
        PokeB(*buffer, 1)
        PokeB(*buffer + 1, Len(username))
        PokeS(*buffer + 2, username)
        k = 2 + Len(username)
        PokeB(*buffer + k, Len(userpass))
        PokeS(*buffer + k + 1, userpass)
        SendNetworkData(netid, *buffer, Len(userpass) + 1 + k)
        ;Check if Username/Password is accepted
        check_timeout.l = ElapsedMilliseconds() + ( timeout * 1000 )
        Repeat
          Delay(10)
          If NetworkClientEvent(netid) = 2
            ReceiveNetworkData(netid, *buffer, 2)
            passver.l = PeekB(*buffer) & 255
            status.l = PeekB(*buffer + 1) & 255
            Break
          EndIf
        Until check_timeout < ElapsedMilliseconds()
        If check_timeout < ElapsedMilliseconds() Or passver <> 1 Or status <> 0
          FreeMemory(*buffer)
          CloseNetworkConnection(netid)
          ProcedureReturn #False
        EndIf
      EndIf
      ;-Phase 3 SOCK5
      ;Send Connect-Request
      PokeB(*buffer, 5)
      PokeB(*buffer + 1, 1)
      PokeB(*buffer + 2, 0)
      Select IsIP( ip_to_connect )
        Case 0
          PokeB(*buffer + 3, 3)
          PokeB(*buffer + 4, Len(ip_to_connect))
          For i = 1 To Len(ip_to_connect)
            PokeB(*buffer + 4 + i, Asc(Mid(ip_to_connect, i, 1)))
          Next i
          cont.l = 4 + i
        Case 1
          PokeB(*buffer + 3, 1)
          For i = 1 To 4
            PokeB(*buffer + 3 + i, Val(StringField(ip_to_connect, i, ".")) & 255)
          Next i
          cont.l = 8
        Case 2
          PokeB(*buffer + 3, 4)
          For i = 1 To 6
            PokeB(*buffer + 3 + i, Val(StringField(ip_to_connect, i, ".")) & 255)
          Next i
          cont.l = 10
      EndSelect
      hi.l = Int(port_to_connect / 256)
      lo.l = port_to_connect - (256 * hi)
      PokeB(*buffer + cont, hi)
      PokeB(*buffer + cont + 1, lo)
      SendNetworkData(netid, *buffer, cont + 2)
      ;Now Check the reply
      check_timeout.l = ElapsedMilliseconds() + ( timeout * 1000 )
      Repeat
        Delay(10)
        If NetworkClientEvent(netid) = 2
          length.l = ReceiveNetworkData(netid, *buffer, 1024)
          ver.l = PeekB(*buffer) & 255
          reply.l = PeekB(*buffer + 1) & 255
          reserved.l = PeekB(*buffer + 2) & 255
          atyp.l = PeekB(*buffer + 3) & 255
          Break
        EndIf
      Until check_timeout < ElapsedMilliseconds()
      If check_timeout < ElapsedMilliseconds() Or ver <> 5 Or reply <> 0 Or reserved <> 0
        FreeMemory(*buffer)
        CloseNetworkConnection(netid)
        ProcedureReturn #False
      EndIf
      Select atyp
        Case 1
          ;IPv4
          ip.s = Str(PeekB(*buffer + 4) & 255) + "." + Str(PeekB(*buffer + 5) & 255) + "."
          ip + Str(PeekB(*buffer + 6) & 255) + "." + Str(PeekB(*buffer + 7) & 255)
          port.l = (PeekB(*buffer + 8) & 255) * 256
          port + (PeekB(*buffer + 9) & 255)
        Case 3
          ;Name
          ip.s = ""
          For i = 1 To (PeekB(*buffer + 4) & 255)
            ip + Chr(PeekB(*buffer + 4 + i) & 255)
          Next i
          port.l = (PeekB(*buffer + 4 + i) & 255) * 256
          port + (PeekB(*buffer + 5 + i) & 255)
        Case 4
          ;IPv6
          ip.s = Str(PeekB(*buffer + 4) & 255) + "." + Str(PeekB(*buffer + 5) & 255) + "."
          ip + Str(PeekB(*buffer + 6) & 255) + "." + Str(PeekB(*buffer + 7) & 255)  + "."
          ip + Str(PeekB(*buffer + 8) & 255) + "." + Str(PeekB(*buffer + 9) & 255)
          port.l = (PeekB(*buffer + 10) & 255) * 256
          port + (PeekB(*buffer + 11) & 255)
      EndSelect
      ;Following IP and Port is just for information... 
      ;this is proxy-internal and not necessarily the same as ip_to_connect/port_to_connect
      Debug "Internal Proxy-IP:" + ip
      Debug "Internal Proxy-Port:" + Str(port)
      FreeMemory(*buffer)
      ProcedureReturn netid

  EndSelect

EndProcedure
Tommeh
Enthusiast
Enthusiast
Posts: 149
Joined: Sun Aug 29, 2004 2:25 pm
Location: United Kingdom

Post by Tommeh »

Wow! Invaluable for networking apps where you may need to connect via a user defined proxy like an IRC client, I'll find great use for this thanks :-)
Tranquil
Addict
Addict
Posts: 952
Joined: Mon Apr 28, 2003 2:22 pm
Location: Europe

Post by Tranquil »

Does this work for anyone!?

I tried everything here at work but could not get any connection to any server. (Tried FTP and IRC services).

Eg:

Code: Select all


OpenConsole()
res=Proxy_Connect("wwwproxy.arcor.db.de",8000,"www.danceyourmusic.com",21,0,"","",120)
PrintN(Str(res))

Input()
End

Other applications, like TotalCommaner, works fine with these settings.

Greetings!
Tranquil
rsts
Addict
Addict
Posts: 2736
Joined: Wed Aug 24, 2005 8:39 am
Location: Southwest OH - USA

Post by rsts »

executable started

then nothing

doesn't attempt to hit the internet - at least my firewall doesn't say anything.

cheers
okasvi
Enthusiast
Enthusiast
Posts: 150
Joined: Wed Apr 27, 2005 9:41 pm
Location: Finland

Post by okasvi »

rsts wrote:executable started

then nothing

doesn't attempt to hit the internet - at least my firewall doesn't say anything.

cheers

:shock: you did make it connect somewhere with Proxy_Connect() right?
User avatar
Kukulkan
Addict
Addict
Posts: 1396
Joined: Mon Jun 06, 2005 2:35 pm
Location: germany
Contact:

Re: http, SOCKS4,5 - Proxy-Connection

Post by Kukulkan »

I have a question to this source: How do I utilize it?

Do I have to call this function at first and upon this I can use standard Windows API functions to connect (like InternetOpen_() and InternetOpenUrl_())? Or how is that meant?

Kukulkan
Tranquil
Addict
Addict
Posts: 952
Joined: Mon Apr 28, 2003 2:22 pm
Location: Europe

Re: http, SOCKS4,5 - Proxy-Connection

Post by Tranquil »

Kukulkan wrote:I have a question to this source: How do I utilize it?

Do I have to call this function at first and upon this I can use standard Windows API functions to connect (like InternetOpen_() and InternetOpenUrl_())? Or how is that meant?

Kukulkan
MS provides own solutions to access the internet through a proxy using InetOpen_() for example. The above code returns a unique PB-ID for the connection. If you want to combine it with winsock API of windows you can convert the NetID to a socket handle which means, that you can use every API command which accepts socket handles.
Tranquil
User avatar
Kukulkan
Addict
Addict
Posts: 1396
Joined: Mon Jun 06, 2005 2:35 pm
Location: germany
Contact:

Re: http, SOCKS4,5 - Proxy-Connection

Post by Kukulkan »

Thank you Tranquil,

In the meanwhile I made it using

Code: Select all

; set proxy username
Ret.l = InternetSetOption_(request_handle.l, #INTERNET_OPTION_PROXY_USERNAME, strUsername.s, Len(strUsername.s));
; set proxy password
Ret.l = InternetSetOption_(request_handle.l, #INTERNET_OPTION_PROXY_PASSWORD, strPassword.s, Len(strPassword.s))
and it works fine.

Kukulkan
Post Reply