现在已完成了与代理的连接测试,用户名密码验证也可通过.
问题是我不知道如何利用代理与服务器交换数据.
打个比方:大家都用QQ,QQ设置里有socks5代理,我现在就是实现了它的测试这一步,现在就是要利用代理实现登录注册等功能.会了登录就会注册了,关键是第一步迈不出!请这方面的高手帮帮忙,有源码最好!
问题是我不知道如何利用代理与服务器交换数据.
打个比方:大家都用QQ,QQ设置里有socks5代理,我现在就是实现了它的测试这一步,现在就是要利用代理实现登录注册等功能.会了登录就会注册了,关键是第一步迈不出!请这方面的高手帮帮忙,有源码最好!
如 webrequest 里的proxy 属性吗?
其实就是拿到一个 Socket 时有区别, 拿到后就一样了, public class Proxy
{
#region members
string _targetHost;
ushort _targetPort;
int _proxyTimeout = 500;// timeout in sec
ProxyType _proxyType;
string _proxyHost;
ushort _proxyPort;
string _proxyUser;
string _proxyPassword;
static readonly string[] socks5ErrorMessages = {
"Operation completed successfully.",//操作成功完成
"General SOCKS server failure.",//常规服务器失败
"Connection not allowed by ruleset.",//连接不被允许
"Network unreachable.",//网络不能到达
"Host unreachable.",//主机不能到达
"Connection refused.",//连接被拒绝
"TTL expired.",//TTL期满
"Command not supported.",//不支持的命令
"Address type not supported.",//不被支持的地址类型
"Unknown error."//未名的错误
}; #endregion #region properties
public string TargetHost
{
get { return _targetHost; }
set { _targetHost = value; }
} public ushort TargetPort
{
get { return _targetPort; }
set { _targetPort = value; }
} public ProxyType ProxyType
{
get { return _proxyType; }
} public string ProxyHost
{
get { return _proxyHost; }
set { _proxyHost = value; }
} public ushort ProxyPort
{
get { return _proxyPort; }
set { _proxyPort = value; }
} public string ProxyUser
{
get { return _proxyUser; }
set { _proxyUser = value; }
} public string ProxyPassword
{
get { return _proxyPassword; }
set { _proxyPassword = value; }
}
#endregion #region constructors
public Proxy(ProxyType proxyType)
{
_proxyType = proxyType;
}
#endregion #region GetSocket
internal Socket GetSocket()
{
Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
socket.SendTimeout = _proxyTimeout;
socket.ReceiveTimeout = _proxyTimeout; switch (_proxyType)
{
case ProxyType.None:
socket.Connect(_targetHost, _targetPort);
break;
case ProxyType.Socks5:
connectToSocks5Proxy(socket, _proxyHost, _proxyPort, _proxyUser, _proxyPassword);
socks5connectToTarget(socket, _targetHost, _targetPort);
break;
default:
throw new ArgumentOutOfRangeException("not supported proxy type");
}
return socket;
}
#endregion #region private
static void connectToSocks5Proxy(Socket socket, string proxyHost,
ushort port, string proxyuser, string proxypassword)
{
// 请求
byte[] requestBuffer = new byte[257];
// 应答
byte[] responseBuffer = new byte[257];
ushort nIndex;
// 客户端连到服务器后, 然后就发送请求来协商版本和认证方法:
socket.Connect(proxyHost, port); nIndex = 0;
requestBuffer[nIndex++] = 0x05; // V 5. [版本]
requestBuffer[nIndex++] = 0x02; // 2 种验证方式[方法的数目]
requestBuffer[nIndex++] = 0x00; // X'00' 不需要认证 [方法1]
requestBuffer[nIndex++] = 0x02; // X'02' 用户名/密码[方法2]
socket.Send(requestBuffer, nIndex, SocketFlags.None); // 收到2个字节的应答, 填充到response中, 如果不是两个字节, 则抛出异常
int nGot = socket.Receive(responseBuffer, 2, SocketFlags.None);
if (nGot != 2)
throw new Exception("代理服务器应答错误"); // 连接成功
// 当前定义的方法有:
// X'00' 不需要认证
// X'01' GSSAPI
// X'02' 用户名/密码
// X'03' -- X'7F' 由IANA分配
// X'80' -- X'FE' 为私人方法所保留的
// X'FF' 没有可以接受的方法
switch (responseBuffer[1])
{
case 0xFF:
throw new Exception("代理服务器没有可以使用的验证方式");
break;
case 0x02:
loginToSocks5Proxy(socket, proxyuser, proxypassword);
break;
}
} static void loginToSocks5Proxy(Socket socket, string proxyuser, string proxypassword)
{
byte[] request = new byte[257];
byte[] response = new byte[257];
ushort nIndex;
byte[] rawBytes; nIndex = 0;
request[nIndex++] = 0x05; // Version 5.
// 加入 user name
// 一个字节,放UserName的长度
request[nIndex++] = (Byte)proxyuser.Length;
rawBytes = Encoding.Default.GetBytes(proxyuser);
// 将userName 加入
rawBytes.CopyTo(request, nIndex);
nIndex += (ushort)rawBytes.Length; // 加入 password
// 一个字节,放PassWord的长度
request[nIndex++] = (Byte)proxypassword.Length;
rawBytes = Encoding.Default.GetBytes(proxypassword);
rawBytes.CopyTo(request, nIndex);
nIndex += (ushort)rawBytes.Length; // 发送 Username/Password 请求
socket.Send(request, nIndex, SocketFlags.None); // 收到2个字节的应答,填充到response中
int nGot = socket.Receive(response, 2, SocketFlags.None);
if (nGot != 2)
{
throw new Exception("从 proxy server 返回错误的应答.");
}
if (response[1] != 0x00) //返回如下的报文字节序列映像为:0x01 | 验证结果标志-.0x00 验证通过, 其余均表示有故障
{
throw new Exception("错误的 Usernaem/Password.");
}
}
{
// 这个函数只实现了connect 命令
//
// +----+-----+-------+------+----------+----------+
// |VER | CMD | RSV | ATYP | DST.ADDR | DST.PORT |
// +----+-----+-------+------+----------+----------+
// | 1 | 1 | X'00' | 1 | Variable | 2 |
// +----+-----+-------+------+----------+----------+
//
// CMD 命令
// o CONNECT X'01'
// o BIND X'02'
// o UDP ASSOCIATE X'03'
//
// ATYP 地址类型
// o IPv4 : X'01'
// o 网址 : X'03'
// o IPv6 : X'04'
//
// DST.ADDR 目标地址
// DST.PORT 目标端口
byte[] requestBuffer = new byte[257];
byte[] responseBuffer = new byte[257];
ushort nIndex; byte[] rawBytes;
nIndex = 0;
requestBuffer[nIndex++] = 0x05; // version 5.
requestBuffer[nIndex++] = 0x01; // command = connect.
requestBuffer[nIndex++] = 0x00; // Reserve = 必须是 0x00 IPAddress targetAddress = null;
if (!IPAddress.TryParse(targetIp, out targetAddress))
{
try
{
IPHostEntry iphe = Dns.GetHostEntry(targetIp);
targetAddress = iphe.AddressList[0];
}
catch
{
}
} if (targetAddress != null)
{
switch (targetAddress.AddressFamily)//目的地址
{
case AddressFamily.InterNetwork://IPV4
requestBuffer[nIndex++] = 0x01;
rawBytes = targetAddress.GetAddressBytes();
rawBytes.CopyTo(requestBuffer, nIndex);
nIndex += (ushort)rawBytes.Length;
break;
case AddressFamily.InterNetworkV6://IPV6
requestBuffer[nIndex++] = 0x04;
rawBytes = targetAddress.GetAddressBytes();
rawBytes.CopyTo(requestBuffer, nIndex);
nIndex += (ushort)rawBytes.Length;
break;
}
}
else
{
// 目标地址是域名
requestBuffer[nIndex++] = 0x03; // 地址是域名
requestBuffer[nIndex++] = Convert.ToByte(targetIp.Length); // 该地址的长度
rawBytes = Encoding.Default.GetBytes(targetIp);
rawBytes.CopyTo(requestBuffer, nIndex);
nIndex += (ushort)rawBytes.Length;
} // 使用 big-edian 字节顺序
byte[] portBytes = BitConverter.GetBytes(targetPort);
for (int i = portBytes.Length - 1; i >= 0; i--)
{
requestBuffer[nIndex++] = portBytes[i];
}
// 发送连接请求
socket.Send(requestBuffer, nIndex, SocketFlags.None);
int len = socket.Receive(responseBuffer); //获得没有固定长度的应答 // 应答格式
// +----+-----+-------+------+----------+----------+
// |VER | REP | RSV | ATYP | BND.ADDR | BND.PORT |
// +----+-----+-------+------+----------+----------+
// | 1 | 1 | X'00' | 1 | Variable | 2 |
// +----+-----+-------+------+----------+----------+
//
// o VER 版本: X'05'
// o REP
// o X'00' 成功
// o X'01' 普通的SOCKS服务器请求失败
// o X'02' 现有的规则不允许的连接
// o X'03' 网络不可达
// o X'04' 主机不可达
// o X'05' 连接被拒
// o X'06' TTL超时
// o X'07' 不支持的命令
// o X'08' 不支持的地址类型
// o X'09'到X'FF' 未定义
// o RSV 保留
// o ATYP 地址类型
// o IPv4 : X'01'
// o 网址 : X'03'
// o IPv6 : X'04'
// o BND.ADDR 服务器绑定的地址
// o BND.PORT 以网络字节顺序表示的服务器绑定的端口
if (responseBuffer[1] != 0x00)
{
if (responseBuffer[1] >= socks5ErrorMessages.Length)
{
String message = System.Text.Encoding.Default.GetString(responseBuffer, 0, len);
throw new Exception(message);
}
else
throw new Exception(socks5ErrorMessages[responseBuffer[1]]);
} Byte addrType = responseBuffer[3];
int bndAddrLength = len - 6;
byte[] bndAddrBuffer = new byte[bndAddrLength];
System.Array.Copy(responseBuffer, 4, bndAddrBuffer, 0, bndAddrLength); String what = System.Text.Encoding.UTF8.GetString(bndAddrBuffer); Byte bndPort1 = responseBuffer[len - 2];
Byte bndPort2 = responseBuffer[len - 1];
}
#endregion }
socks5connectToTarget()这个方法是连接目标服务器吗?这个方法中的socket参数怎么给?是上面方法中的还是新建的?
如果是连接的,那么连接之后怎么登录?可以模拟下吗?Dobzhansky高手帮下忙
public POP3Client(Proxy proxy, string username, string password)
{
_proxy = proxy;
_userName = username;
_password = password;
_socket = _proxy.GetSocket(); // 管他是代理还是直接连接呢, proxy 负责了 // 下面就当 socket 是目的机器
// 初始化流
_networkStream = new NetworkStream(_socket, true);
_streamReader = new StreamReader(_networkStream, System.Text.Encoding.ASCII);
_streamWriter = new StreamWriter(_networkStream, System.Text.Encoding.ASCII);
_streamWriter.AutoFlush = true; string answer = _streamReader.ReadLine();
}
/// 登陆到服务器验证该用户名密码的用户是否为合法用户
/// </summary>
/// <param name="uid">用户名</param>
/// <param name="pwd">密码</param>
/// <returns>验证结果</returns>
public static string[] CheckLogin(string uid,string pwd,TcpClient tcpClient)
{
pwd = EncryptAndDecrypt.MD5(uid+pwd);
//string login = EncryptAndDecrypt.EncryptDES("login");
Stream stream = tcpClient.GetStream();
UTF8Encoding utf8 = new UTF8Encoding();
byte[] bytes = utf8.GetBytes("login;" + uid + ";" + pwd);
stream.Write(bytes, 0, bytes.Length);
byte[] bb = new byte[1024];
stream.Read(bb,0,bb.Length);
string message = Encoding.UTF8.GetString(bb);
string[] param = message.Split(';');
stream.Close();
tcpClient.Close();
return param;
}
/// 类增加两个成员变量保存代理类, socket 类
Proxy _proxy;
Socket _socket;
// 上面两个成员的
void createProxy()
{
_proxy= new Proxy(ProxyType.Socks5);
_proxy.ProxyHost = "192.168.0.1";
_proxy.ProxyPort = 1080;
_proxy.TargetHost = "pop3.126.com";//目标主机和端口根据自己需要修改
_proxy.TargetPort = 110; }
/// <summary>
/// 登陆到服务器验证该用户名密码的用户是否为合法用户
/// </summary>
/// <param name="uid">用户名</param>
/// <param name="pwd">密码</param>
/// <returns>验证结果</returns>
public static string[] CheckLogin(string uid,string pwd,TcpClient tcpClient)
{
pwd = EncryptAndDecrypt.MD5(uid+pwd);
//string login = EncryptAndDecrypt.EncryptDES("login");
/// 注意这里
createProxy();
_socket = _proxy.GetSocket(); // 这个调用发生连接到 proxy, proxy 连接到远程主机
Stream stream = new NetworkStream(_socket, true);;
UTF8Encoding utf8 = new UTF8Encoding();
byte[] bytes = utf8.GetBytes("login;" + uid + ";" + pwd);
stream.Write(bytes, 0, bytes.Length);
byte[] bb = new byte[1024];
stream.Read(bb,0,bb.Length);
string message = Encoding.UTF8.GetString(bb);
string[] param = message.Split(';');
stream.Close();
tcpClient.Close();
return param;
}
{
// TODO: Add your control notification handler code here
CString m_sError;
ClientSock.Create();
//if( !ClientSock.Connect("61.145.123.202",3128) )
if( !ClientSock.Connect("211.92.143.19",3128) )
//if( !ClientSock.Connect("WWW.TOM.COM",80) )
{
m_sError = _T("不能连接到代理服务器!");
ClientSock.Close();
MessageBox(m_sError);
return ;
} char buff[600] = {0};
// sprintf( buff, "%s%s:%d%s","CONNECT ","219.201.39.50",21," HTTP/1.1\r\nUser-Agent: MyApp/0.1\r\n\r\n");
sprintf( buff, "%s%s:%d%s","CONNECT ","219.201.39.50",21," HTTP/1.1\r\nUser-Agent: CERN-LineMode/2.15 libwww/2.17b3\r\n\r\n");
// sprintf( buff, "%s%s:%d%s","CONNECT ","www.tom.com",80," HTTP/1.1\r\nUser-Agent: CERN-LineMode/2.15 libwww/2.17b3\r\n\r\n");
// sprintf( buff, "%s%s","GET ","HTTP://WWW.TOM.COM HTTP/1.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 ;
}
/* if( strstr(buff, "Error 403") )
{
//return GoError(PROXYERROR_PROXYDISABLE); //代理服务器拒绝请求
}
if( strstr(buff, "407 Proxy authentication required") ) //需要身份验证
{
//return GoError(PROXYERROR_USERNAMEORPASSWORD); //用户身份校检不成功
}
if( strstr(buff, "Connection refuesed") )
{
//return GoError(PROXYERROR_CONNECTHOSTSERVER); //通过代理连接主站不成功
}
if( strstr(buff, "Access Denied") )
{
//return GoError(PROXYERROR_USERNAMEORPASSWORD); //用户身份校检不成功
}
if(strstr(buff, "Connection refused by Remote Host") )
{
//return GoError(PROXYERROR_CONNECTHOSTSERVER); //通过代理连接主站不成功
}
ClientSock.Close();
*/
//连接已经建立,发送及接收数据
memset(buff,0,600);
strcpy(buff,"Hello!");
ClientSock.Send(buff,sizeof(buff));
memset(buff,0,600);
ClientSock.Receive(buff,600);
MessageBox(buff);
ClientSock.Close();
}