登录 用户中心() [退出] 后台管理 注册
 

热门搜索:
您的位置:首页 >> 程序员下载区 >> 程序员下载区 >> 主题: Socks4、Socks5、Http代理
标题 Socks4、Socks5、Http代理
clq
浏览(1047) 2008-01-03 13:51:46 发表 编辑

关键字:

先看一段代码. 来自 http://topic.csdn.net/t/20020725/02/900001.html
--------------------------------------------------
穿透代理服务器编程
http://www.programfan.com/showarticle.asp?id=1772
关键词:代理服务器、Socks4、Socks5、Http代理
在网络程序设计过程中,我们经常要与各种类型的代理服务器打交道,比如在企业内部网通过代理去访问Internet网上的服务器等等,一般代理服务器支持几种常见的代理协议标准,如Socks4,Socks5,Http代理,其中Socks5需要用户验证,代理相对复杂。我在查阅RFC文档和相关资料后,特总结一些TCP协议穿透代理服务器的程序片断,希望对大家有所帮助。
//使用到的结构
struct sock4req1
{
char VN;
char CD;
unsigned short Port;
unsigned long IPAddr;
char other[1];
};

struct sock4ans1
{
char VN;
char CD;
};

struct sock5req1
{
char Ver;
char nMethods;
char Methods[255];
};

struct sock5ans1
{
char Ver;
char Method;
};

struct sock5req2
{
char Ver;
char Cmd;
char Rsv;
char Atyp;
char other[1];
};

struct sock5ans2
{
char Ver;
char Rep;
char Rsv;
char Atyp;
char other[1];
};

struct authreq
{
char Ver;
char Ulen;
char Name[255];
char PLen;
char Pass[255];
};

struct authans
{
char Ver;
char Status;
};

//通过Socks4方式代理
if( !ClientSock.Connect( g_ProxyInfo.m_strProxyIP,g_ProxyInfo.m_nProxyPort) )
{
m_sError = _T("不能连接到代理服务器!");
ClientSock.Close();
return FALSE;
}
char buff[100];
memset(buff,0,100);
struct sock4req1 *m_proxyreq;
m_proxyreq = (struct sock4req1 *)buff;
m_proxyreq->VN = 4;
m_proxyreq->CD = 1;
m_proxyreq->Port = ntohs(GetPort());
m_proxyreq->IPAddr = inet_addr(GetServerHostName());
ClientSock.Send(buff,9);
struct sock4ans1 *m_proxyans;
m_proxyans = (struct sock4ans1 *)buff;
memset(buff,0,100);
ClientSock.Receive(buff,100);
if(m_proxyans->VN != 0 || m_proxyans->CD != 90)
{
m_sError = _T("通过代理连接主站不成功!");
ClientSock.Close();
return FALSE;
}

//通过Socks5方式代理
if( !ClientSock.Connect( g_ProxyInfo.m_strProxyIP,g_ProxyInfo.m_nProxyPort) )
{
m_sError = _T("不能连接到代理服务器!");
ClientSock.Close();
return FALSE;
}
char buff[600];
struct sock5req1 *m_proxyreq1;
m_proxyreq1 = (struct sock5req1 *)buff;
m_proxyreq1->Ver = 5;
m_proxyreq1->nMethods = 2;
m_proxyreq1->Methods[0] = 0;
m_proxyreq1->Methods[1] = 2;
ClientSock.Send(buff,4);
struct sock5ans1 *m_proxyans1;
m_proxyans1 = (struct sock5ans1 *)buff;
memset(buff,0,600);
ClientSock.Receive(buff,600);
if(m_proxyans1->Ver != 5 || (m_proxyans1->Method!=0 && m_proxyans1->Method!=2))
{
m_sError = _T("通过代理连接主站不成功!");
ClientSock.Close();
return FALSE;
}
if(m_proxyans1->Method == 2)
{
int nUserLen = strlen(g_ProxyInfo.m_strProxyUser);
int nPassLen = strlen(g_ProxyInfo.m_strProxyPass);
struct authreq *m_authreq;
m_authreq = (struct authreq *)buff;
m_authreq->Ver = 1;
m_authreq->Ulen = nUserLen;
strcpy(m_authreq->Name,g_ProxyInfo.m_strProxyUser);
m_authreq->PLen = nPassLen;
strcpy(m_authreq->Pass,g_ProxyInfo.m_strProxyPass);
ClientSock.Send(buff,513);
struct authans *m_authans;
m_authans = (struct authans *)buff;
memset(buff,0,600);
ClientSock.Receive(buff,600);
if(m_authans->Ver != 1 || m_authans->Status != 0)
{
m_sError = _T("代理服务器用户验证不成功!");
ClientSock.Close();
return FALSE;
}
}
struct sock5req2 *m_proxyreq2;
m_proxyreq2 = (struct sock5req2 *)buff;
m_proxyreq2->Ver = 5;
m_proxyreq2->Cmd = 1;
m_proxyreq2->Rsv = 0;
m_proxyreq2->Atyp = 1;
unsigned long tmpLong = inet_addr(GetServerHostName());
unsigned short port = ntohs(GetPort());
memcpy(m_proxyreq2->other,&tmpLong,4);
memcpy(m_proxyreq2->other+4,&port,2);
ClientSock.Send(buff,sizeof(struct sock5req2)+5);
struct sock5ans2 *m_proxyans2;
memset(buff,0,600);
m_proxyans2 = (struct sock5ans2 *)buff;
ClientSock.Receive(buff,600);
if(m_proxyans2->Ver != 5 || m_proxyans2->Rep != 0)
{
m_sError = _T("通过代理连接主站不成功!");
ClientSock.Close();
return FALSE;
}

//通过HTTP方式代理
if( !ClientSock.Connect( g_ProxyInfo.m_strProxyIP,g_ProxyInfo.m_nProxyPort) )
{
m_sError = _T("不能连接到代理服务器!");
ClientSock.Close();
return FALSE;
}
char buff[600];
sprintf( buff, "%s%s:%d%s","CONNECT ",GetServerHostName(),GetPort()," HTTP/1.1\r\nUser-Agent: MyApp/0.1\r\n\r\n");
ClientSock.Send(buff,strlen(buff)); //发送请求
memset(buff,0,600);
ClientSock.Receive(buff,600);
if(strstr(buff, "HTTP/1.0 200 Connection established") == NULL) //连接不成功
{
m_sError = _T("通过代理连接主站不成功!");
ClientSock.Close();
return FALSE;
}
我们一般先与代理服务器连通,然后向代理服务器发送代理验证的用户名和密码(如果需要,如Socks5代理),验证成功后,再向代理服务器发送需要连接的目的地址和端口。以上代码仅用于TCP连接,如果在内部网侦听或通过UDP协议发送信息,可查阅RFC1829等文档资料。

--------------------------------------------------
这些代码的 socks5 的有用户名的认证部分有错,用 authreq 结构来传认证数据是不对的,因为协议表明的内容应该是紧凑的,不可能有一个 255 的空内存.正确的生成方法见下面的代码.原理可看后面的跟贴.

sprintf(buff, "%c%c%s%c%s", 1, nUserLen, proxy_user, nPassLen, proxy_pass);

clq
2008-1-3 13:53:59 发表 编辑

下面是比较详细的协议说明. 来自 http://www.tongyi.net/develop/vb/1053923.html
--------------------------------------------------
统一教学网-IT知识库
Web本站
首页 >> 程序开发 >> Visual Basic
VB6 中 使用Winsock穿越各种代理的实现(TCP协议)
作者:VirtualDesktop


感谢 Oleg Gdalevich 和 CSDN 用户 zyg0(影子)对本文(程序)所做的贡献

本文中引用的RFC文档内容归原作者所有

转载本文请标明出处

本文作者:吴滂

本文中提及的程序可在 枕善居 http://www.mndsoft.com/blog/blogview.asp?logID=494 下载

关于用vb的winsock穿透代理的讨论归讨论,一直没有什么源代码放出,现在我就放源出来,省的某些人拿这所谓的"技术"去骗钱.

由于缺乏测试环境,本程序只在我自己编写的代理模拟器上测试过,其结果和腾讯QQ,MSN,网易泡泡穿越该模拟器时得出的结果基本一致.因此,代码可能有错误的地方,请各位有条件的用户自行改正,请见谅!

首先,是基础知识,也就是RFC文档.这个是必看内容.我的程序就是基于这些文档写出.下面是各RFC的连接,为了准确,我先提供英文版的连接,在下面的介绍中再把关键部分翻译成中文.另外,要纠正一个错误.国内很多文章说socks5代理的用户名/密码校验标准在 RFC 1928里有说明,其实这是一个完全错误的说法(我很怀疑写那文章的人有没有看过RFC),socks5用户名/密码校验标准其实是在 RFC 1929 里面说明的.

RFC 1928 - socks5 代理标准

RFC 1929 - socks5 代理用户名/密码校验标准

RFC ???? - socks4 代理标准

RFC 2616 - HTTP1.1 标准



我们现在直入正题:先说socks5的TCP穿透(有了这个例子大家自己照这可以写UDP穿透)

首先和代理服务器连接-直接用winsock去connect指定的地址端口(通常是1080)即可.然后进入细节商议阶段.

细节商议--无用户名/密码校验

RFC 1928 中对于细节商议的第一步是这样描述的:

The client connects to the server, and sends a version
identifier/method selection message:

+----+----------+----------+
|VER | NMETHODS | METHODS |
+----+----------+----------+
| 1 | 1 | 1 to 255 |
+----+----------+----------+

The VER field is set to X''''05'''' for this version of the protocol. The
NMETHODS field contains the number of method identifier octets that
appear in the METHODS field.


The server selects from one of the methods given in METHODS, and
sends a METHOD selection message:

+----+--------+
|VER | METHOD |
+----+--------+
| 1 | 1 |
+----+--------+

If the selected METHOD is X''''FF'''', none of the methods listed by the
client are acceptable, and the client MUST close the connection.

The values currently defined for METHOD are:

o X''''00'''' NO AUTHENTICATION REQUIRED ---------无用户密码 00
o X''''01'''' GSSAPI ---------??? GSSAPI ?
o X''''02'''' USERNAME/PASSWORD ---------有用户密码 02
o X''''03'''' to X''''7F'''' IANA ASSIGNED
o X''''80'''' to X''''FE'''' RESERVED FOR PRIVATE METHODS
o X''''FF'''' NO ACCEPTABLE METHODS ---------失败 255

The client and server then enter a method-specific sub-negotiation.



换言之,就是向服务器发送三个字节的Byte数组,由于是无须用户/密码校验,展开来写是 05 01 00

然后服务器返回两个字节的信息,第一个字节固定,第而个字节是说明,如果是16进制的FF(即十进制255)表示连接失败(o X''''FF'''' NO ACCEPTABLE METHODS)根据上面的列表,我们连接成功应该第二字节为 00.

然后我们进入第二步,请看以下RFC说明:

Once the method-dependent subnegotiation has completed, the client
sends the request details. If the negotiated method includes
encapsulation for purposes of integrity checking and/or
confidentiality, these requests MUST be encapsulated in the method-
dependent encapsulation.

The SOCKS request is formed as follows:

+----+-----+-------+------+----------+----------+
|VER | CMD | RSV | ATYP | DST.ADDR | DST.PORT |
+----+-----+-------+------+----------+----------+
| 1 | 1 | X''''00'''' | 1 | Variable | 2 |
+----+-----+-------+------+----------+----------+

Where:

o VER protocol version: X''''05'''' ------------- 固定 05
o CMD
o CONNECT X''''01'''' ------------- TCP方式 01
o BIND X''''02''''
o UDP ASSOCIATE X''''03'''' ------------- UDP方式 03
o RSV RESERVED ------------- 固定 00
o ATYP address type of following address
o IP V4 address: X''''01'''' ------------- IPv4 01
o DOMAINNAME: X''''03''''
o IP V6 address: X''''04''''
o DST.ADDR desired destination address
o DST.PORT desired destination port in network octet
order

The SOCKS server will typically evaluate the request based on source
and destination addresses, and return one or more reply messages, as
appropriate for the request type.


发送 05 01 00 01 + 目的地址(4字节) + 目的端口(2字节),目的地址和端口都是16进制码(不是字符串)。
例202.103.190.27 - 7201
则发送的信息为:05 01 00 01 CA 67 BE 1B 1C 21
(CA=202 67=103 BE=190 1B=27 1C21=7201)

关于我是怎么把16进制码换成10进制的,请自己看程序

最后,接受服务器返回数据,看RFC:

+----+-----+-------+------+----------+----------+
|VER | REP | RSV | ATYP | BND.ADDR | BND.PORT |
+----+-----+-------+------+----------+----------+
| 1 | 1 | X''''00'''' | 1 | Variable | 2 |
+----+-----+-------+------+----------+----------+

Where:

o VER protocol version: X''''05'''' ------------ 固定 05
o REP Reply field:
o X''''00'''' succeeded ------------ 若为 00 成功 其余可以都看成失败
o X''''01'''' general SOCKS server failure
o X''''02'''' connection not allowed by ruleset
o X''''03'''' Network unreachable
o X''''04'''' Host unreachable
o X''''05'''' Connection refused
o X''''06'''' TTL expired
o X''''07'''' Command not supported
o X''''08'''' Address type not supported
o X''''09'''' to X''''FF'''' unassigned
o RSV RESERVED
o ATYP address type of following address

o IP V4 address: X''''01''''
o DOMAINNAME: X''''03''''
o IP V6 address: X''''04''''
o BND.ADDR server bound address
o BND.PORT server bound port in network octet order

Fields marked RESERVED (RSV) must be set to X''''00''''.


可见,对于返回信息,只须判断第二字节是否为00.若为 00 连接成功,剩下的操作和直连一样,Winsock可直接用SendData 和 GetData 发送\接受数据.

下面介绍需要验证用户名/密码的socks5穿透

第一步还是发送三个字节,只是内容有变,展开来写为: 05 01 02

服务器返回信息也有所不同,正确的返回为 05 02

成功后发送用户/密码信息,请看RFC 说明:

Once the SOCKS V5 server has started, and the client has selected the
Username/Password Authentication protocol, the Username/Password
subnegotiation begins. This begins with the client producing a
Username/Password request:

+----+------+----------+------+----------+
|VER | ULEN | UNAME | PLEN | PASSWD |
+----+------+----------+------+----------+
| 1 | 1 | 1 to 255 | 1 | 1 to 255 |
+----+------+----------+------+----------+

The VER field contains the current version of the subnegotiation,
which is X''''01''''. The ULEN field contains the length of the UNAME field
that follows. The UNAME field contains the username as known to the
source operating system. The PLEN field contains the length of the
PASSWD field that follows. The PASSWD field contains the password
association with the given UNAME.

The server verifies the supplied UNAME and PASSWD, and sends the
following response:

+----+--------+
|VER | STATUS |
+----+--------+
| 1 | 1 |
+----+--------+

A STATUS field of X''''00'''' indicates success. If the server returns a
`failure'''' (STATUS value other than X''''00'''') status, it MUST close the
connection.

即 发送 01 + 用户名长度(一字节) + 转换成16进制码的用户名 + 密码长度(一字节) + 转换成16进制码的密码,关于如何把用户名和密码转换为10进制Byte数组,请自己看程序.

然后服务器返回两个字节的信息,只须判断第二字节,00 为成功,其余为失败.

剩下的步骤和无用户名密码校验是一样的,即

发送 05 01 00 01 + 目的地址(4字节) + 目的端口(2字节),目的地址和端口都是16进制码(不是字符串)。
例202.103.190.27 - 7201
则发送的信息为:05 01 00 01 CA 67 BE 1B 1C 21
(CA=202 67=103 BE=190 1B=27 1C21=7201)

关于我是怎么把16进制码换成10进制的,请自己看程序

最后接受服务器返回信息.对于返回信息,只须判断第二字节是否为00.若为 00 连接成功,剩下的操作和直连一样,Winsock可直接用SendData 和 GetData 发送\接受数据.

socks4的TCP穿透(事实上,socks4只支持TCP穿透)

无用户名/密码验证

请看 RFC 说明

1) CONNECT

The client connects to the SOCKS server and sends a CONNECT request when
it wants to establish a connection to an application server. The client
includes in the request packet the IP address and the port number of the
destination host, and userid, in the following format.

+----+----+----+----+----+----+----+----+----+----+....+----+
| VN | CD | DSTPORT | DSTIP | USERID |NULL|
+----+----+----+----+----+----+----+----+----+----+....+----+
1 1 2 4 variable 1

VN is the SOCKS protocol version number and should be 4. CD is the
SOCKS command code and should be 1 for CONNECT request. NULL is a byte
of all zero bits.


我们首先还是连接服务器,然后根据RFC的格式发送数据给服务器.由于是无用户密码验证,我们需要发送9个字节的数据,展开写为 04 01 + 目标端口(2字节) + 目标IP(4字节) + 00,奇怪的是,表中的USERID部分似乎是没有用的,我参照过大量的C++代码,代码中都没有体现该部分.

至于如何转换目标端口和IP为相应的Byte数组,请自己看示例程序.消息发出后,服务器会返回信息,格式如下:

+----+----+----+----+----+----+----+----+
| VN | CD | DSTPORT | DSTIP |
+----+----+----+----+----+----+----+----+
1 1 2 4

VN is the version of the reply code and should be 0. CD is the result
code with one of the following values:

90: request granted -------------- 成功
91: request rejected or failed -------------- 失败
92: request rejected becasue SOCKS server cannot connect to
identd on the client
93: request rejected because the client program and identd
report different user-ids

The remaining fields are ignored.


根据RFC的说法,代理服务器返回8字节的数据,我们只要判断第二字节是否为90即可,若是90连接成功,否则失败.剩下的操作和直连一样,Winsock可直接用SendData 和 GetData 发送\接受数据.

HTTP1.1 代理的穿透

由于RFC 2616过于冗长,加上HTTP代理穿透的步骤比socks简单,这里就不详细说明了,我只给出连接的步骤和发送数据格式.

第一步仍然是用Winsock去连接代理服务器.第二步为发送请求字符,其格式为:

无用户名/密码校验 格式:

"CONNECT" + 空格 + 目标连接地址 + ":" + 目标连接端口 + 空格 + "HTTP/1.1" + Chr(13) + Chr(10) + "Host:" + 空格 + 目标连接地址 + ":" + 目标连接端口 + Chr(13) + Chr(10) + Chr(13) + Chr(10)

用户名/密码验证格式:

"CONNECT" + 空格 + 目标连接地址 + ":" + 目标连接端口 + 空格 + "HTTP/1.1" + Chr(13) + Chr(10) + "Host:" + 空格 + 目标连接地址 + ":" + 目标连接端口 + Chr(13) + Chr(10) + "Authorization: Basic" + 空格 + 经Base64加密过后的[用户名:密码] + Chr(13) + Chr(10) + Chr(13) + Chr(10) + "Proxy-Authorization: Basic" + 空格 + 经Base64加密过后的[用户名:密码] + Chr(13) + Chr(10) + Chr(13) + Chr(10)

发送请求完毕后,将收到代理的回应,根据RFC说明(注意 Status-Line 和 Status-Code):

6 Response

After receiving and interpreting a request message, a server responds
with an HTTP response message.

Response = Status-Line ; Section 6.1
*(( general-header ; Section 4.5
| response-header ; Section 6.2
| entity-header ) CRLF) ; Section 7.1
CRLF
[ message-body ] ; Section 7.2

6.1 Status-Line

The first line of a Response message is the Status-Line, consisting
of the protocol version followed by a numeric status code and its
associated textual phrase, with each element separated by SP
characters. No CR or LF is allowed except in the final CRLF sequence.

Status-Line = HTTP-Version SP Status-Code SP Reason-Phrase CRLF

6.1.1 Status Code and Reason Phrase

The Status-Code element is a 3-digit integer result code of the
attempt to understand and satisfy the request. These codes are fully
defined in section 10. The Reason-Phrase is intended to give a short
textual description of the Status-Code. The Status-Code is intended
for use by automata and the Reason-Phrase is intended for the human
user. The client is not required to examine or display the Reason-
Phrase.

The first digit of the Status-Code defines the class of response. The
last two digits do not have any categorization role. There are 5
values for the first digit:

- 1xx: Informational - Request received, continuing process

- 2xx: Success - The action was successfully received,
understood, and accepted

- 3xx: Redirection - Further action must be taken in order to
complete the request

- 4xx: Client Error - The request contains bad syntax or cannot
be fulfilled

- 5xx: Server Error - The server failed to fulfill an apparently
valid request

The individual values of the numeric status codes defined for
HTTP/1.1, and an example set of corresponding Reason-Phrase''''s, are
presented below. The reason phrases listed here are only
recommendations -- they MAY be replaced by local equivalents without
affecting the protocol.

Status-Code =
"100" ; Section 10.1.1: Continue
| "101" ; Section 10.1.2: Switching Protocols
| "200" ; Section 10.2.1: OK
| "201" ; Section 10.2.2: Created
| "202" ; Section 10.2.3: Accepted
| "203" ; Section 10.2.4: Non-Authoritative Information
| "204" ; Section 10.2.5: No Content
| "205" ; Section 10.2.6: Reset Content
| "206" ; Section 10.2.7: Partial Content
| "300" ; Section 10.3.1: Multiple Choices
| "301" ; Section 10.3.2: Moved Permanently
| "302" ; Section 10.3.3: Found
| "303" ; Section 10.3.4: See Other
| "304" ; Section 10.3.5: Not Modified
| "305" ; Section 10.3.6: Use Proxy
| "307" ; Section 10.3.8: Temporary Redirect
| "400" ; Section 10.4.1: Bad Request
| "401" ; Section 10.4.2: Unauthorized
| "402" ; Section 10.4.3: Payment Required
| "403" ; Section 10.4.4: Forbidden
| "404" ; Section 10.4.5: Not Found
| "405" ; Section 10.4.6: Method Not Allowed
| "406" ; Section 10.4.7: Not Acceptable

| "407" ; Section 10.4.8: Proxy Authentication Required
| "408" ; Section 10.4.9: Request Time-out
| "409" ; Section 10.4.10: Conflict
| "410" ; Section 10.4.11: Gone
| "411" ; Section 10.4.12: Length Required
| "412" ; Section 10.4.13: Precondition Failed
| "413" ; Section 10.4.14: Request Entity Too Large
| "414" ; Section 10.4.15: Request-URI Too Large
| "415" ; Section 10.4.16: Unsupported Media Type
| "416" ; Section 10.4.17: Requested range not satisfiable
| "417" ; Section 10.4.18: Expectation Failed
| "500" ; Section 10.5.1: Internal Server Error
| "501" ; Section 10.5.2: Not Implemented
| "502" ; Section 10.5.3: Bad Gateway
| "503" ; Section 10.5.4: Service Unavailable
| "504" ; Section 10.5.5: Gateway Time-out
| "505" ; Section 10.5.6: HTTP Version not supported
| extension-code


可知,如果连接成功,服务器返回的信息是 "HTTP/" + 代理版本 + "200" + 描述("Connection established")

所以我们只要判断返回的信息是否以"http"开头,是否存在" 200 "字眼即可.

以下是关键函数的源代码:

Public Function ProxyStep(ProxyType As Integer, PStep As Integer)
Dim SendByte() As Byte
If ProxyType = 0 Then ''''@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ sock4代理
If PStep = 1 Then

ReDim SendByte(0 To 8) As Byte

SendByte(0) = 4 '''' 04

SendByte(1) = 1 '''' 01

SendByte(2) = Int(DestPort / 256)

SendByte(3) = DestPort Mod 256

SendByte(4) = GetIPByte(1, DestIP)

SendByte(5) = GetIPByte(2, DestIP)

SendByte(6) = GetIPByte(3, DestIP)

SendByte(7) = GetIPByte(4, DestIP)

SendByte(8) = 0 ''''最后要以 0 结束

Form1.Winsock1.SendData SendByte()

ConnStep = PStep + 1
Exit Function

End If

If PStep = 2 Then ''''代理回复,第二字节为 90 为成功,其余值为失败
If Asc(Mid(RevBuffer, 2, 1)) <> 90 Then
Debug.Print Asc(Mid(RevBuffer, 2, 1))
MsgBox "连接sock4代理失败!", 48, "错误"
Form1.Winsock1.Close
ConnStep = 0
Exit Function
Else
Form1.Label8.Caption = "连接目标服务器成功!"
ConnStep = -1
Form2.Show
Exit Function
End If

End If
End If

''''*******************下面的例子有大量重复代码,是为了让大家更清楚地了解sock5穿透过程,大家可以拿回去自己优化 **********************************

If ProxyType = 1 Then ''''@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ sock5代理

Select Case PStep


Case 1
ReDim SendByte(0 To 2) As Byte ''''第一步 无验证发送 05 01 00, 有验证发送 05 02 02
SendByte(0) = 5 '''' 05
SendByte(1) = 1 ''''01 ''''在有用户密码验证时此字节是 1 还是 2 有诸多争论,现以腾讯QQ穿越代理模拟器时发送的数据为准,如有错误,请自己修改!
SendByte(2) = IIf(Form1.Check1.Value = 0, 0, 2) ''''00 或 02
Form1.Winsock1.SendData SendByte()
ConnStep = PStep + 1
Exit Function

Case 2 ''''代理回复
If Asc(Mid(RevBuffer, 2, 1)) = 255 Then ''''FF (255) 为失败
MsgBox "连接代理失败!", 64
Form1.Winsock1.Close
ConnStep = 0
Exit Function

End If
If Asc(Mid(RevBuffer, 2, 1)) = 0 And Asc(Mid(RevBuffer, 1, 1)) = 5 Then ''''若代理回复 05 00 为无验证连接成功
Form1.Label8.Caption = "连接成功!无验证"

ReDim SendByte(0 To 9) As Byte ''''第二步 无验证 发送连接请求
SendByte(0) = 5
SendByte(1) = 1
SendByte(2) = 0
SendByte(3) = 1
SendByte(4) = GetIPByte(1, DestIP)
SendByte(5) = GetIPByte(2, DestIP)
SendByte(6) = GetIPByte(3, DestIP)
SendByte(7) = GetIPByte(4, DestIP)
SendByte(8) = Int(DestPort / 256) ''''把10进制端口分成两个字节
SendByte(9) = DestPort Mod 256 ''''把10进制端口分成两个字节
Form1.Winsock1.SendData SendByte()

ConnStep = ConnStep + 1

Exit Function

End If

If Asc(Mid(RevBuffer, 2, 1)) = 2 And Asc(Mid(RevBuffer, 1, 1)) = 5 Then ''''第二步 有用户名密码验证 成功为 05 02
Form1.Label8.Caption = "连接成功!有验证"
ReDim SendByte(0 To 2 + Len(UserName) + Len(UserPassword)) As Byte

SendByte(0) = 1

SendByte(1) = Len(UserName)

MemCopy SendByte(2), ByVal UserName, Len(UserName) ''''将用户名转换

SendByte(2 + Len(UserName)) = Len(UserPassword)

MemCopy SendByte(3 + Len(UserName)), ByVal UserPassword, Len(UserPassword) ''''将密码转换


Form1.Winsock1.SendData SendByte()

ConnStep = ConnStep + 1

Exit Function
End If

Case 3
If Asc(Mid(RevBuffer, 2, 1)) <> 0 And Form1.Check1.Value = 1 Then ''''有验证,验证失败 代理回复第二字节为 00 验证成功,其余值为失败
MsgBox "sock5代理校验用户名、密码失败!", 48, "错误"
Form1.Winsock1.Close
ConnStep = 0
Exit Function
End If

If Asc(Mid(RevBuffer, 2, 1)) = 0 And Form1.Check1.Value = 1 Then ''''有验证,验证成功,回复值第二字节为 00 ,其余值为失败
Form1.Label8.Caption = "连接成功!有验证!"
ReDim SendByte(0 To 9) As Byte ''''发送连接请求
SendByte(0) = 5
SendByte(1) = 1
SendByte(2) = 0
SendByte(3) = 1
SendByte(4) = GetIPByte(1, DestIP)
SendByte(5) = GetIPByte(2, DestIP)
SendByte(6) = GetIPByte(3, DestIP)
SendByte(7) = GetIPByte(4, DestIP)
SendByte(8) = Int(DestPort / 256) ''''把10进制端口分成两个字节
SendByte(9) = DestPort Mod 256 ''''把10进制端口分成两个字节
Form1.Winsock1.SendData SendByte()

ConnStep = ConnStep + 1

Exit Function
End If

If Asc(Mid(RevBuffer, 2, 1)) = 0 And Form1.Check1.Value = 0 Then

Form1.Label8.Caption = "连接目标服务器成功!" ''''无验证的最后一步,代理回复第二字节为 00 成功,其余值为失败
ConnStep = -1
Form2.Show
Exit Function
End If


If Asc(Mid(RevBuffer, 2, 1)) <> 0 And Form1.Check1.Value = 0 Then

MsgBox "连接目标服务器失败!", 48, "错误" ''''无验证的最后一步,代理回复第二字节为 00 成功,其余值为失败
ConnStep = 0
Form1.Winsock1.Close

Exit Function
End If

Case 4 ''''只有有验证才会用到这一步
If Asc(Mid(RevBuffer, 2, 1)) <> 0 Then
MsgBox "sock5代理连接目标服务器失败!", 48, "错误"
ConnStep = 0
Form1.Winsock1.Close
Exit Function
Else
Form1.Label8.Caption = "连接目标服务器成功!"
ConnStep = -1
Form2.Show
Exit Function
End If



End Select
End If

If ProxyType = 2 Then ''''@@@@@@@@@@@@@@@@@@@@@@@@HTTP1.1代理
If PStep = 1 Then ''''无用户名密码验证
If Form1.Check1.Value = 0 Then
HTTPHeader = "CONNECT " & Form1.Text5.Text & ":" & Form1.Text6.Text & _
" HTTP/1.1" & Chr(13) & Chr(10) & "Host: " & Form1.Text5.Text & ":" & Form1.Text6.Text & Chr(13) & Chr(10) & Chr(13) & Chr(10)

ConnStep = PStep + 1
Form1.Winsock1.SendData HTTPHeader
Exit Function

End If

If Form1.Check1.Value = 1 Then '''' 有用户名密码验证

HTTPHeader = "CONNECT " & Form1.Text5.Text & ":" & Form1.Text6.Text & _
" HTTP/1.1" & Chr(13) & Chr(10) & "Host: " & Form1.Text5.Text & ":" & _
Form1.Text6.Text & Chr(13) & Chr(10) & "Authorization: Basic " & StrtoBase64(Form1.Text3.Text & _
":" & Form1.Text4.Text) & Chr(13) & Chr(10) & Chr(13) & Chr(10) & "Proxy-Authorization: Basic " & _
StrtoBase64(Form1.Text3.Text & ":" & Form1.Text4.Text) & Chr(13) & Chr(10) & Chr(13) & Chr(10)
'''' Chr(13) & Chr(10) 能否直接用vbCrLf ? 我不知道
Debug.Print HTTPHeader
ConnStep = PStep + 1
Form1.Winsock1.SendData HTTPHeader
Exit Function
End If



End If

If PStep = 2 Then ''''代理服务器回复,格式:HTTP/[代理版本] [状态代码] [状态说明]

If LCase(Left(RevBuffer, 4)) = "http" And Mid(" 200 ", 1) <> 0 Then ''''状态代码为 200 为成功

Form1.Label8.Caption = "连接目标服务器成功!"

Form2.Show
ConnStep = -1

Else

MsgBox "HTTP1.1代理连接目标服务器失败!", 48, "错误"
ConnStep = 0
Form1.Winsock1.Close
Exit Function

End If

End If
End If

End Function

clq
2008-1-5 16:53:34 发表 编辑

isa 的 http 代理还是有点特殊的. 好象只能连接 433 端口.

void httpconnect(base_socket & so, char * host, int port,
char * proxy_host, int proxy_port,
char * proxy_user, char * proxy_pass)
{

so.connect(proxy_host, proxy_port);

//代理的请求
//通过HTTP方式代理

char buff[600];
memset(buff, 0, sizeof(buff));
//sprintf(buff, "%s%s:%d%s", "CONNECT", host, port, " HTTP/1.1\r\nUser-Agent: MyApp/0.1\r\n\r\n");
//"CONNECT" + 空格 + 目标连接地址 + ":" + 目标连接端口 + 空格 + "HTTP/1.1" + Chr(13) + Chr(10) + "Host:" + 空格 + 目标连接地址 + ":" + 目标连接端口 + Chr(13) + Chr(10) + Chr(13) + Chr(10)
sprintf(buff,
"CONNECT %s:%d HTTP/1.1\r\n"
"Host: %s:%d\r\n"
//"User-Agent: MyApp/0.1\r\n\r\n"
"User-Agent: MyApp\r\n\r\n"
"\r\n"
,
host, port,
host, port
);

//tm(QQ)的请求为
// CONNECT http.tencent.com:443 HTTP/1.1
// Accept: */*
// Content-Type: text/html
// Proxy-Connection: Keep-Alive
// Content-length: 0

//sprintf(buff,
// "CONNECT %s:443 HTTP/1.1""\r\n"
// "Accept: */*""\r\n"
// "Content-Type: text/html""\r\n"
// "Proxy-Connection: Keep-Alive""\r\n"
// "Content-length: 0""\r\n"
// "\r\n"
// ,
// //host, port,
// host
// );


//之所以用 443 端口是很可能是因为 isa 这样的代理服务器只允许其连接这一端口


so.send_buf(buff,strlen(buff)); //发送请求
memset(buff,0,600);
int r = so.recv(buff,600);
if(strstr(buff, "HTTP/1.0 200 Connection established") == NULL) //连接不成功
{
printf("通过代理连接主站不成功!");
//ClientSock.Close();
//return FALSE;
}
}


总数:2 页次:1/1 首页 尾页  


发表评论:
文本/html模式切换 插入图片 文本/html模式切换


附件:




Copyright © 2005-2012 CLQ工作室, All Rights Reserved

CLQ工作室 版权所有