环境介绍:
客户端软件安装在一台处在代理环境中的PC上,通过代理上互联网,代理协议是socks4 端口1080,也提供http协议代理,端口是808,没有用户名密码验证。代理服务器上设置了DNS服务器的地址。客户端软件通过socks4代理协议,是通过域名访问服务器端的,采用C#开发.net framwork 2.0。
问题描述:
如果在PC机的网络配置上的DNS服务器上填写了代理服务器的IP地址,那么就可以正确完成域名解析连上服务器端,如果PC上的DNS服务器配置上不填,那么就无法正确解析域名,提示an invalid IP address was specified。但通过IE浏览器(配置好了http代理的相关信息)就能访问互联网上的网站。想寻求解决办法,正常来说是不用配PC上的DNS服务器地址的,但不知道用哪个方法或函数,可以实现将域名发到代理服务器,让代理服务器连接DNS服务器来解析域名,将IP地址返回到PC的客户端软件上。
下面是我们使用的解析dns的代码,从完整代码中抽取出来了:
string ipTemp = string.Empty;
if (!IsCorrenctIP(m_ServerIP))
{
ipTemp = Dns.GetHostEntry(m_ServerIP).AddressList[0].ToString();
m_ServerIP = ipTemp;
}
if (!IsCorrenctIP(m_AssemblyServerIP))
{
ipTemp =Dns.GetHostEntry(m_AssemblyServerIP).AddressList[0].ToString();
m_AssemblyServerIP = ipTemp;
}
if (!IsCorrenctIP(m_DataDownloadServerIP))
{
ipTemp=Dns.GetHostEntry(m_DataDownloadServerIP).AddressList[0].ToString();
m_DataDownloadServerIP = ipTemp;
}
客户端软件安装在一台处在代理环境中的PC上,通过代理上互联网,代理协议是socks4 端口1080,也提供http协议代理,端口是808,没有用户名密码验证。代理服务器上设置了DNS服务器的地址。客户端软件通过socks4代理协议,是通过域名访问服务器端的,采用C#开发.net framwork 2.0。
问题描述:
如果在PC机的网络配置上的DNS服务器上填写了代理服务器的IP地址,那么就可以正确完成域名解析连上服务器端,如果PC上的DNS服务器配置上不填,那么就无法正确解析域名,提示an invalid IP address was specified。但通过IE浏览器(配置好了http代理的相关信息)就能访问互联网上的网站。想寻求解决办法,正常来说是不用配PC上的DNS服务器地址的,但不知道用哪个方法或函数,可以实现将域名发到代理服务器,让代理服务器连接DNS服务器来解析域名,将IP地址返回到PC的客户端软件上。
下面是我们使用的解析dns的代码,从完整代码中抽取出来了:
string ipTemp = string.Empty;
if (!IsCorrenctIP(m_ServerIP))
{
ipTemp = Dns.GetHostEntry(m_ServerIP).AddressList[0].ToString();
m_ServerIP = ipTemp;
}
if (!IsCorrenctIP(m_AssemblyServerIP))
{
ipTemp =Dns.GetHostEntry(m_AssemblyServerIP).AddressList[0].ToString();
m_AssemblyServerIP = ipTemp;
}
if (!IsCorrenctIP(m_DataDownloadServerIP))
{
ipTemp=Dns.GetHostEntry(m_DataDownloadServerIP).AddressList[0].ToString();
m_DataDownloadServerIP = ipTemp;
}
//************************************************
//
//重点在说明如何实现Socket5代理协议方式通讯
//http://blog.sina.com.cn/zhujiechang
//
//************************************************
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Net.Sockets;
namespace sampleProxySocket
{
class Program
{
// Declare the delegate prototype to send data back to the form
static byte[] m_byBuff = new byte[256]; // Recieved data buffer
static void Main(string[] args)
{
//重点来
try
{
Console.WriteLine("socket5使用示例!");
string proxyAddress = "192.168.1.2";
int proxyPort = 1080;
string destAddress = "www.csdn.net";
int destPort = 80;
IPEndPoint proxyIp = new IPEndPoint(IPAddress.Parse(proxyAddress), proxyPort);
Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); socket.Connect(proxyIp); //代理地址 Shake_hands(socket); //协议握手 IPEndPoint destIp = new IPEndPoint(Dns.GetHostEntry(destAddress).AddressList[0], destPort);
Protocol_Request(socket, destIp); //协议请求 //正常的请求
SetupRecieveCallback(socket);
socket.Send(Encoding.ASCII.GetBytes(
string.Format("GET / HTTP/1.1 \r\nAccept: */* \r\nAccept-Language: zh-cn \r\nHost:{0}\r\n\r\n",
destAddress)));
}
代理协议内容如下:和代理握手完成之后,要进行一个请求连接,这个就是对远程服务器的连接,我们知道当前既然连接的是代理服务器,我们实际上发送数据的对象并不是它,也就是我们要告诉代理服务器去连接真实的某某,现在就是在做这一步了。
SOCKS请求的格式如下:
VER CMD RSV ATYP DST.ADDR DST.PROT
1 1 X’00’ 1 Variable 2 其中
· VER 协议版本: X’05’
· CMD
· CONNECT:X’01’
· BIND:X’02’
· UDP ASSOCIATE:X’03’
· RSV 保留
· ATYP 后面的地址类型
· IPV4:X’01’
· 域名:X’03’
· IPV6:X’04’'
· DST.ADDR 目的地址
· DST.PORT 以网络字节顺序出现的端口号
SOCKS服务器会根据源地址和目的地址来分析请求,然后根据请求类型返回一个或多个应答。
ATYP字段中描述了地址字段(DST.ADDR,BND.ADDR)所包含的地址类型:
· X'01'
基于IPV4的IP地址,4个字节长
· X'03'
基于域名的地址,地址字段中的第一字节是以字节为单位的该域名的长度,没有结尾的NUL字节。
· X'04'
基于IPV6的IP地址,16个字节长。
Variable表示该域的长度是可变的。所以是不是可以将下面代码里面的data[3]赋值为03,然后直接用域名,向代理服务器发送向互联网上服务器的请求。
if (proxyType == InnerCommEnum.ProxyType.PT_Socks4)//socks4代理服务
{
IPEndPoint ipEndPoint = new IPEndPoint(IPAddress.Parse(m_proxyIP), Convert.ToInt32(m_proxyPost));
//根据IP地址和端口号创建远程终结点
EndPoint endPoint = (EndPoint)ipEndPoint;
try
{
m_ClientMainSocket.Connect(endPoint);
m_ClientMainSocket.ReceiveTimeout = 10000;
//连接请求
byte[] data = new byte[9];
data[0] = 4;//VER 协议版本
data[1] = 1;//CMD CONNECT:X’01’BIND:X’02’ UDP ASSOCIATE:X’03’
// data[2] = 0;//RSV 保留
// data[3] = 1;//ATYP 后面的地址类型 IPV4:X’01’域名:X’03’ IPV6:X’04’' int length = 0;
byte[] buff = new byte[1024];
IPEndPoint destIP = new IPEndPoint(IPAddress.Parse(m_ServerIP), Convert.ToInt32(m_ServerPort));
Array.Copy(BitConverter.GetBytes(
IPAddress.HostToNetworkOrder(destIP.Port)), 2, data, 2, 2);//以网络字节顺序出现的端口号
Array.Copy(destIP.Address.GetAddressBytes(), 0, data, 4, 4); //DST.ADDR 目的地址
m_ClientMainSocket.Send(data, SocketFlags.None);