scar socks5 proxy library
iv used it to load google through tor, and to connect to irc through tor
SCAR Code:
{
scar socks5 proxy library by yakman
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
}
{
read rfc1928 and rfc1929
}
type
RemoteAddress = record
ipv4: Boolean;
host: string; //used if ipv4=false
ip: array[0..3] of byte; //used it ipv4=true
end;
SocketBuffer = record
fd: Integer;
pos, len: Integer;
buf: string;
end;
Socks5Auth = record
UseAuth: Boolean;
user, pass: string;
end;
//have to make a simple buffering interface here..
procedure StartSocketByteBuffer(var buffer: SocketBuffer; fd: integer);
begin
buffer.fd:= fd;
buffer.pos:= 1;
end;
function SocketRead(var buffer: SocketBuffer): Char;
var
b: string;
begin
if(buffer.pos >= buffer.len+1)then
begin
ReadConnectionData(buffer.fd, b);
buffer.buf:= b;
buffer.pos:= 1;
buffer.len:= Length(buffer.buf);
end;
Result:= buffer.buf[buffer.pos];
buffer.pos:= buffer.pos + 1;
end;
{
Start a socks5 connection
fd - socket handle
addr - address the socks5 server should connect to
when this function returns, the values in the record
will be filled with the addr that the socket
on the socks5 server is bounded to.
port - port the socks5 server should connect to
when this function returns, it will be filled with
the port that the socket on the socks5 server is
bounded to.
auth - username/password to be offered, if any
return true on success
}
function InitSocks5(fd: Integer; var addr: RemoteAddress; var port: Integer; var auth: Socks5Auth): Boolean;
var
p: string;
buffer: SocketBuffer;
c: char;
f: Integer;
begin
Result:= True;
StartSocketByteBuffer(buffer, fd);
//send handshake
p:= #05; //version
if(auth.UseAuth)then
p:= p
+ #02 //number of methods
+ #00 //method no auth
+ #02 //username/password
else
p:= p
+ #01 //number of methods
+ #00; //method no auth
SendConnectionData(fd, p);
//read version
c:= SocketRead(buffer);
if(c <> #05)then
begin
Result:= False;
Writeln('Socks wrong version: ' + inttostr(ord(c)));
Exit;
end;
//read method
c:= SocketRead(buffer);
if(auth.UseAuth)then
begin
if(c <> #00)and(c <> #02)then
begin
Result:= False;
Writeln('Socks wrong method: ' + inttostr(ord(c)));
Exit;
end;
if(c = #02)then //user/pass auth
begin
p:= #05
+ Chr(Length(auth.user) and $ff) + auth.user
+ Chr(Length(auth.pass) and $ff) + auth.pass;
SendConnectionData(fd, p);
SocketRead(buffer); //reading version again
if(SocketRead(buffer) <> #00)then //status
begin
Result:= False;
writeln('Failed auth');
Exit;
end;
end;
end
else
begin
if(c <> #00)then
begin
Result:= False;
Writeln('Socks wrong method: ' + inttostr(ord(c)));
Exit;
end;
end;
//send request
p:= #05 + //version
#01 + //cmd connect
#00;//reserved
if(addr.ipv4)then
begin
p:= p + #01 + //ipv4
Chr(addr.ip[0]) + Chr(addr.ip[1]) + Chr(addr.ip[2]) + Chr(addr.ip[3]);
end
else
begin
p:= p + #03 + //domain name
Chr(Length(addr.host) and $ff) + addr.host;
end;
//add port
p:= p + Chr((port shr 8) and $ff) + Chr(port and $ff);
SendConnectionData(fd, p);
//reading reply
SocketRead(buffer); //version
c:= SocketRead(buffer);
if(c <> #00)then
begin
Result:= False;
Writeln('Socks reply not equal to success: ' + inttostr(ord(c)));
Exit;
end;
SocketRead(buffer); //reserved
c:= SocketRead(buffer); //address type
case c of
#01: begin //ipv4 address
addr.ipv4:= True;
for f:=0 to 3 do
addr.ip[f]:= Ord(SocketRead(buffer)); //read ipv4 addr
end;
#03: begin //domain name
addr.ipv4:= False;
addr.host:= '';
c:= SocketRead(buffer);
for f:=1 to ord(c) do
addr.host:= addr.host + SocketRead(buffer);
end;
#04: begin //ipv6
//writeln('warning - ipv6 not implemented');
for f:=1 to 16 do
SocketRead(buffer); //read ipv6 addr
end;
end;
port:= (Ord(SocketRead(buffer)) shl 8) or (Ord(SocketRead(buffer)));
end;
procedure LoadGoogle;
var
fd: Integer;
s: string;
addr: RemoteAddress;
port: Integer;
auth: Socks5Auth;
begin
writeln('connecting');
fd:= OpenConnection('localhost', 9050, 10000);
if(fd < 0)then
begin
writeln('OpenConnection()');
Exit;
end;
writeln('negociating proxy server');
{
addr.ipv4:= True;
addr.ip[0]:= 209;
addr.ip[1]:= 85;
addr.ip[2]:= 229;
addr.ip[3]:= 147;
}
addr.ipv4:= False;
addr.host:= 'www.google.co.uk';
port:= 80;
auth.UseAuth:= True;
auth.user:= 'socks5user';
auth.pass:= 'socks5pass';
if(not InitSocks5(fd, addr, port, auth))then
begin
FreeConnection(fd);
writeln('error starting socks');
Exit;
end;
if(addr.ipv4)then
s:= Inttostr(addr.ip[0]) + '.'
+ Inttostr(addr.ip[1]) + '.'
+ Inttostr(addr.ip[2]) + '.'
+ Inttostr(addr.ip[3])
else
s:= addr.host;
writeln('remote socket bound to ' + s + ':' + Inttostr(port));
SendConnectionData(fd,
'GET / HTTP/1.1' + #13 + #10 +
'Accept: */*' + #13 + #10 +
'User-Agent: scar' + #13 + #10 +
'Host: [url]www.google.co.uk[/url]' + #13 + #10 +
'Connection: close' + #13 + #10 +
#13 + #10
);
writeln('waiting for responce');
repeat
ReadConnectionData(fd, s);
Writeln(s);
Sleep(50);
until(s = '');
writeln('end');
FreeConnection(fd);
end;
begin
LoadGoogle;
end.