随笔 - 298  文章 - 377  trackbacks - 0
<2007年9月>
2627282930311
2345678
9101112131415
16171819202122
23242526272829
30123456

常用链接

留言簿(34)

随笔分类

随笔档案

文章档案

相册

收藏夹

搜索

  •  

最新评论

阅读排行榜

评论排行榜

/*************************************  
    *   一个基础的代理服务器类  
    *************************************  
    */  
  import   java.net.*;  
  import   java.io.*;  
   
  public   class   HttpProxy   extends   Thread   {  
          static   public   int   CONNECT_RETRIES=5;  
          static   public   int   CONNECT_PAUSE=5;  
          static   public   int   TIMEOUT=50;  
          static   public   int   BUFSIZ=1024;  
          static   public   boolean   logging   =   false;  
          static   public   OutputStream   log=null;  
          //   传入数据用的Socket  
          protected   Socket   socket;  
          //   上级代理服务器,可选  
          static   private   String   parent=null;  
          static   private   int   parentPort=-1;  
          static   public   void   setParentProxy(String   name,   int   pport)   {  
  parent=name;  
  parentPort=pport;  
          }  
   
          //   在给定Socket上创建一个代理线程。  
          public   HttpProxy(Socket   s)   {   socket=s;   start();   }  
   
          public   void   writeLog(int   c,   boolean   browser)   throws   IOException   {  
  log.write(c);  
          }  
   
          public   void   writeLog(byte[]   bytes,int   offset,   int   len,   boolean   browser)   throws   IOException   {  
  for   (int   i=0;i<len;i++)   writeLog((int)bytes[offset+i],browser);  
          }  
   
   
          //   默认情况下,日志信息输出到  
          //   标准输出设备  
          //   派生类可以覆盖它  
          public   String   processHostName(String   url,   String   host,   int   port,   Socket   sock)   {  
  java.text.DateFormat   cal=java.text.DateFormat.getDateTimeInstance();  
  System.out.println(cal.format(new   java.util.Date())   +   "   -   "   +   url   +   "   "    
                              +   sock.getInetAddress()+"\n");  
  return   host;  
          }  
   
   
   
          //   执行操作的线程  
          public   void   run()   {  
  String   line;  
  String   host;  
  int   port=80;  
                  Socket   outbound=null;  
  try   {  
          socket.setSoTimeout(TIMEOUT);  
          InputStream   is=socket.getInputStream();  
          OutputStream   os=null;  
          try   {  
                                  //   获取请求行的内容  
  line="";  
  host="";  
  int   state=0;  
  boolean   space;  
  while   (true)   {  
          int   c=is.read();  
          if   (c==-1)   break;  
          if   (logging)   writeLog(c,true);  
          space=Character.isWhitespace((char)c);    
          switch   (state)   {  
          case   0:  
  if   (space)   continue;    
                  state=1;  
          case   1:  
  if   (space)   {  
          state=2;  
          continue;  
  }  
  line=line+(char)c;  
  break;  
          case   2:  
  if   (space)   continue;   //   跳过多个空白字符  
                      state=3;  
          case   3:  
  if   (space)   {  
          state=4;    
                                                          //   只取出主机名称部分  
          String   host0=host;  
          int   n;  
          n=host.indexOf("//");  
          if   (n!=-1)   host=host.substring(n+2);  
          n=host.indexOf('/');  
          if   (n!=-1)   host=host.substring(0,n);  
                                                          //   分析可能存在的端口号  
          n=host.indexOf(":");  
          if   (n!=-1)   {    
  port=Integer.parseInt(host.substring(n+1));  
  host=host.substring(0,n);  
          }  
          host=processHostName(host0,host,port,socket);  
          if   (parent!=null)   {  
  host=parent;  
  port=parentPort;  
          }  
          int   retry=CONNECT_RETRIES;  
          while   (retry--!=0)   {  
  try   {  
          outbound=new   Socket(host,port);  
          break;  
  }   catch   (Exception   e)   {   }  
                                                                  //   等待  
  Thread.sleep(CONNECT_PAUSE);  
          }  
          if   (outbound==null)   break;  
          outbound.setSoTimeout(TIMEOUT);  
          os=outbound.getOutputStream();  
          os.write(line.getBytes());  
          os.write('   ');  
          os.write(host0.getBytes());  
          os.write('   ');  
          pipe(is,outbound.getInputStream(),os,socket.getOutputStream());  
          break;  
  }  
  host=host+(char)c;  
  break;  
          }  
  }  
          }  
          catch   (IOException   e)   {   }  
   
          }   catch   (Exception   e)   {   }  
          finally   {  
          try   {   socket.close();}   catch   (Exception   e1)   {}  
          try   {   outbound.close();}   catch   (Exception   e2)   {}  
                }  
          }  
   
   
          void   pipe(InputStream   is0,   InputStream   is1,  
                    OutputStream   os0,     OutputStream   os1)   throws   IOException   {  
  try   {  
          int   ir;  
          byte   bytes[]=new   byte[BUFSIZ];  
          while   (true)   {  
  try   {  
          if   ((ir=is0.read(bytes))>0)   {  
  os0.write(bytes,0,ir);  
  if   (logging)   writeLog(bytes,0,ir,true);  
          }  
          else   if   (ir<0)  
  break;  
  }   catch   (InterruptedIOException   e)   {   }  
  try   {  
          if   ((ir=is1.read(bytes))>0)   {  
  os1.write(bytes,0,ir);  
  if   (logging)   writeLog(bytes,0,ir,false);  
          }  
          else   if   (ir<0)    
  break;  
  }   catch   (InterruptedIOException   e)   {   }  
          }  
  }   catch   (Exception   e0)   {  
          System.out.println("Pipe异常:   "   +   e0);  
  }  
          }  
   
   
          static   public   void   startProxy(int   port,Class   clobj)   {  
  ServerSocket   ssock;  
  Socket   sock;  
                  try   {  
          ssock=new   ServerSocket(port);  
          while   (true)   {  
  Class   []   sarg   =   new   Class[1];  
  Object   []   arg=   new   Object[1];  
  sarg[0]=Socket.class;  
  try   {  
          java.lang.reflect.Constructor   cons   =   clobj.getDeclaredConstructor(sarg);  
          arg[0]=ssock.accept();  
          cons.newInstance(arg);   //   创建HttpProxy或其派生类的实例  
  }   catch   (Exception   e)   {    
          Socket   esock   =   (Socket)arg[0];  
          try   {   esock.close();   }   catch   (Exception   ec)   {}  
  }  
          }  
  }   catch   (IOException   e)   {  
  }  
          }  
   
   
          //   测试用的简单main方法  
          static   public   void   main(String   args[])   {  
  System.out.println("在端口808启动代理服务器\n");  
  HttpProxy.log=System.out;  
  HttpProxy.logging=false;  
  HttpProxy.startProxy(808,HttpProxy.class);  
              }  
          }  
  //   HttpProxy的简单派生类  
  //   不记录主机名字  
  //   在日志输出的每一行前面加上一个'*'  
   
  import   java.io.*;  
  import   java.net.*;  
   
  public   class   SubHttpProxy   extends   HttpProxy   {  
          static   private   boolean   first=true;  
          public   SubHttpProxy(Socket   s)   {  
  super(s);  
          }  
          public   void   writeLog(int   c,   boolean   browser)   throws   IOException   {  
  if   (first)   log.write('*');  
  first=false;  
  log.write(c);  
  if   (c=='\n')   log.write('*');  
          }  
          public   String   processHostName(String   url,   String   host,   int   port,   Socket   sock)   {  
  //   直接返回  
  return   host;  
          }  
          //   测试用的简单main方法  
          static   public   void   main(String   args[])   {  
  System.out.println("在端口808启动代理服务器\n");  
  HttpProxy.log=System.out;  
  HttpProxy.logging=true;  
  HttpProxy.startProxy(808,SubHttpProxy.class);  
              }  
   
   
  }  
posted on 2008-10-21 02:02 聂文龙 阅读(7106) 评论(11)  编辑 收藏 引用

FeedBack:
# re: 代理服务器代码 2008-10-21 02:03 聂文龙
不要心里老是想着只要拿到源代码就可以直接去用,因为对rfc1928、rfc1929研究是必要的,因为在调试程序的时候,你一定要知道协议才可以调,我现在给一些相关的文档给你,也许比那些代码对你更加有用处:

用socks5进行udp发送数据的过程:

你的目的是要和服务器做UDP的数据传送。
步骤:
1,和代理建立tcp联接,(你已经完成)
2,向代理发送版本的请求信息,
我的实现:
void CCommunicator::SendVer ()
{
int datasize = 6;
char tempbuf[6];

tempbuf[0] = 5;
tempbuf[1] = 4;//标示后面所根的字接数
tempbuf[2] = 0;
tempbuf[3] = 1;
tempbuf[4] = 2;
tempbuf[5] = 3;
int senddatalen;
senddatalen = send(m_sock, (char *)tempbuf, 6, 0 );
}
这一步,你已经返回成功,是吗?
如果失败,断开建立的tcp联接,
如果成功,如果需要用户验证则进行步骤3,否则进行4,
3,如果需要用户验证,则
类似:
BOOL CCommunicator::SendUserTest()
{
int usernamelen=0;
int userpasslen=0;
usernamelen = m_strTestUserName.GetLength();
userpasslen = m_strTestUserPass.GetLength();
char tempbuf[100];

tempbuf[0] = 5;
tempbuf[1] = usernamelen;//标示后面所根的字接数
strcpy(&tempbuf[2],m_strTestUserName);

tempbuf[2+usernamelen] = userpasslen;
strcpy((char *)&tempbuf [3+usernamelen] ,m_strTestUserPass);

int senddatalen;
int len;
len = usernamelen +userpasslen + 3;
senddatalen = send(m_sock, (char *)tempbuf, len, 0 );
}
如果失败,断开建立的tcp联接,
如果用户返回成功,步骤4
4,发送请求的协议
类似:
void CCommunicator::SendRequestUDP ()
{

int const datasize = 10;
BYTE tempbuf[datasize];
tempbuf[0] = 5;
tempbuf[1] = 3;//标示UDP连接
tempbuf[2] = 0;
tempbuf[3] = 1;
tempbuf[4] = 0;
tempbuf[5] = 0;
tempbuf[6] = 0;
tempbuf[7] = 0;
*((SHORT*)(&(tempbuf[8]))) = m_uBindUDPPort;
//UDP在客户端绑定的端口,就是你本地机器的做udp数据传送的端口,调用
// socket函数后,再调用bind()来邦定一个端口。
char temp;
temp = tempbuf[8] ;
tempbuf[8] = tempbuf[9];
tempbuf[9] = temp;

int senddatalen = send(m_sock, (char *)tempbuf, datasize, 0 );
}
如果失败,断开建立的tcp联接,
如果返回成功,验证完毕!步骤5
5,真正的数据传送,用代理传送的时候,数据包的前面加上10个字节
类似:
void CCommunicator::CopyDataHead(BYTE * ptempbuf)
{
struct in_addr addr;
addr.s_addr = inet_addr(“202.220.33.333”);//这个ip是服务器端的ip

ptempbuf[0] = 0;
ptempbuf[1] = 0;
ptempbuf[2] = 0;
ptempbuf[3] = 1;
ptempbuf[4] = (char)addr.S_un.S_un_b.s_b1;;
ptempbuf[5] = (char)addr.S_un.S_un_b.s_b2;
ptempbuf[6] = (char)addr.S_un.S_un_b.s_b3;
ptempbuf[7] = (char)addr.S_un.S_un_b.s_b4;

*((SHORT*)(&(ptempbuf[8]))) = m_uServerUDPPort;//服务器的端口,就是你最终要发到那个服务器的端口,也就是你的qq服务器。
char temp;
temp = ptempbuf[8] ;
ptempbuf[8] = ptempbuf[9];
ptempbuf[9] = temp;
}
真正发送的时候类似:
int CCommunicator::SendBufferUDP(LPBYTE lpBuf,int nLen)
{
BYTE tempbuf[1000];
int iHeadData = 0;
struct sockaddr_in her;
her.sin_family = AF_INET;
her.sin_addr.s_addr = inet_addr(m_szProxyAddr);//代理服务器
her.sin_port = htons(m_uSocksPort);//发送请求的时候返回的代理服务器端的端口,记住,这是最重要的。
CopyDataHead(tempbuf);
iHeadData = 10;
nLen=nLen + 10;
int addr_len;
addr_len = sizeof(struct sockaddr);

CopyMemory((char *)&tempbuf[iHeadData],lpBuf,nLen);
int returndatalen = sendto(m_socket,(char *)tempbuf,nLen,0,(struct sockaddr *)&her,addr_len);

}
希望对你有帮助!  回复  更多评论
  
# re: 代理服务器代码 2008-10-21 02:04 聂文龙
传透代理服务器的编程

关键字 代理服务器、Socks4、Socks5、Http代理
原作者姓名 allfresh
文章原始出处 http://www.allfresh.net/program/proxy.htm
正文
在网络程序设计过程中,我们经常要与各种类型的代理服务器打交道,比如在企业内部网通过代理去访问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等文档资料。

<正文完>   回复  更多评论
  
# re: 代理服务器代码 2008-10-21 02:08 聂文龙
使用socks4 socks5 http代理的客户端

///定义的结构
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;
unsigned long IPAddr;
unsigned short Port;

// 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;
};


///////////
///////////代码片段
void CTestDlg::OnSocks4()
{
CString m_sError;
ClientSock.Create();

//Socks4代理服务器端口及地址
//if( !ClientSock.Connect( "195.65.215.38",1080) )
if( !ClientSock.Connect( "192.168.123.194",1080) )
{
m_sError = _T("不能连接到代理服务器!");
ClientSock.Close();
MessageBox(m_sError);
return ;
}

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(21);
m_proxyreq->IPAddr = inet_addr("219.201.39.50");
strcpy(m_proxyreq->other , "");
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();
MessageBox(m_sError);
return ;
}



//连接已经建立,发送及接收数据
memset(buff,0,100);
strcpy(buff,"Hello!");
ClientSock.Send(buff,sizeof(buff));
memset(buff,0,100);
ClientSock.Receive(buff,100);
MessageBox(buff);
ClientSock.Close();

}

void CTestDlg::OnSocks5()
{
// TODO: Add your control notification handler code here
//http://my.nbip.net/homepage/nblulei/ttdl/sockdllb.htm

CString m_sError;
ClientSock.Create();
//Socks5代理服务器端口及地址
//if( !ClientSock.Connect("61.238.12.84",12654) )
if( !ClientSock.Connect("192.168.123.194",1080) )
{
m_sError = _T("不能连接到代理服务器!");
ClientSock.Close();
MessageBox(m_sError);
return ;
}
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();
MessageBox(m_sError);
return ;
}
if(m_proxyans1->Method == 2)
{
int nUserLen = strlen("alon");
int nPassLen = strlen("alon");
struct authreq *m_authreq = {0};
m_authreq = (struct authreq *)buff;
m_authreq->Ver = 1;
m_authreq->Ulen = nUserLen;
strcpy(m_authreq->Name,"alon");
m_authreq->PLen = nPassLen;
strcpy(m_authreq->Pass,"alon");
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();
MessageBox(m_sError);
return ;
}
}
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;
m_proxyreq2->IPAddr = inet_addr("219.201.39.50");
m_proxyreq2->Port = ntohs(21);


ClientSock.Send(buff,sizeof(struct sock5req2));
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();
MessageBox(m_sError);
return ;
}



//连接已经建立,发送及接收数据
memset(buff,0,600);
strcpy(buff,"Hello!");
ClientSock.Send(buff,sizeof(buff));
memset(buff,0,600);
ClientSock.Receive(buff,600);
MessageBox(buff);
ClientSock.Close();
}


void CTestDlg::OnHttp()
{
// 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();


}


/////////
///另附一些http的请求和返回
发送一:
CONNECT 61.135.158.91:80 HTTP/1.1
User-Agent: MyApp/0.1


发送二:
CONNECT 61.135.158.91:80 HTTP/1.1
User-Agent: CERN-LineMode/2.15 libwww/2.17b3


发送三:
CONNECT 127.0.0.1:2222 HTTP/1.0
User-agent: MyApp/1.0
Proxy-authorization: enter xxxxxx


接收一:
HTTP/1.0 403 Forbidden
Server: Topproxy-2.0/
Mime-Version: 1.0
Date: Thu, 18 Nov 2004 16:37:53 GMT
Content-Type: text/html
Content-Length: 718
Expires: Thu, 18 Nov 2004 16:37:53 GMT
X-Squid-Error: ERR_ACCESS_DENIED 0
X-Cache: MISS fro


接收二:
HTTP/1.0 502 Proxy Error ( SSL port specified is not allowed. )
Via: 1.0 PROXY
Pragma: no-cache
Cache-Control: no-cache
Content-Type: text/html

<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
<html>

<head>
<meta http-equiv="Conten"


接收三:
HTTP/1.1 403 Forbidden
Date: Sat, 20 Nov 2004 14:33:13 GMT
Content-Length: 257
Content-Type: text/html
Server: NetCache appliance (NetApp/5.6R1D6)

<HTML>
<HEAD><TITLE>403 Forbidden</TITLE></HEAD>
<BODY>
<H1>Forbidden</H1>
<H4>
You were"



  回复  更多评论
  
# re: 代理服务器代码 2008-10-21 02:12 聂文龙
简单代理服务器C代码实现(SOLARIS)

/*
** 编写:无可非议
** 来源:WWW.20CN.NET
** 注意:请注明转贴来源
*/

#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <signal.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <sys/wait.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <pthread.h>
#include <sys/stat.h>

int m_MainId = 0; //主进程ID
int m_ListenSocket = 0; //侦听套接字
char m_ConnectAddr[256] = {0}; //目标地址
char m_ConnectPort[256] = {0}; //目标端口

/*
** 函数名称: GetListenSocket
** 函数功能: 生成侦听套接字
** 传入参数: Port : 侦听端口
** 传出参数: 无
** 引用函数: 无
** 返回值 : 侦听套接字,为0时表示生成套接字失败,其他为套接字句柄
** 备注 : 无
*/
int GetListenSocket(int Port)
{
struct sockaddr_in m_LisAddr = {0};
int m_Socket = 0;
int m_AddrLen = sizeof(struct sockaddr_in);

//配置端口信息
m_LisAddr.sin_family = AF_INET;
m_LisAddr.sin_port = htons(Port);
m_LisAddr.sin_addr.s_addr = INADDR_ANY;

//创建套接字
if ((m_Socket = socket(AF_INET,SOCK_STREAM,0)) < 0 )
{
//创建套接字失败
return 0;
}

//绑定套接字
if(bind(m_Socket, (sockaddr*)&m_LisAddr , m_AddrLen) < 0 )
{
//绑定套接字失败
close(m_Socket);
return 0;
}

//侦听套接字
if(listen(m_Socket,5))
{
//侦听套接字失败
close(m_Socket);
return 0;
}

//侦听套接字生成成功
return m_Socket;
}

/*
** 函数名称: GetConnectSocket
** 函数功能: 生成连接套接字
** 传入参数: pServerAddr : 连接地址 pServerPort : 连接端口
** 传出参数: 无
** 引用函数: 无
** 返回值 : 连接套接字,为0时表示生成套接字失败,其他为套接字句柄
** 备注 : 无
*/
int GetConnectSocket(char* pServerAddr,char* pServerPort)
{
struct sockaddr_in m_ServerAddr = {0};
int m_AddrLen = sizeof(struct sockaddr_in);
int m_Socket = 0;

//初始化连接信息
m_ServerAddr.sin_addr.S_un.S_addr = inet_addr(pServerAddr);
m_ServerAddr.sin_port = htons(atoi(pServerPort));
m_ServerAddr.sin_family = AF_INET;

//创建发送套接字
m_Socket = socket(AF_INET,SOCK_STREAM,0);
if(m_Socket <= 0)
{
//失败
return NULL;
}

//连接客户计算机
if(connect(m_Socket,(sockaddr*)&m_ServerAddr,m_AddrLen) < 0 )
{
close(m_Socket);
return NULL;
}

//连接成功
return m_Socket;
}

/*
** 函数名称: TransSocket
** 函数功能: 完成套接字数据转发
** 传入参数: m_SendSocket : 发送套接字 m_RecvSocket : 接收套接字
** 传出参数: 无
** 引用函数: 无
** 返回值 : 无
** 备注 : 逆反完成全双工
*/
void TransSocket(int m_SendSocket,int m_RecvSocket)
{
char m_Buf[512 * 1024] = {0};
int ret = 0;
fd_set readset;
struct timeval tm = {0};
tm.tv_sec = 3600 * 24;

FD_ZERO(&readset);
FD_SET(m_RecvSocket,&readset);

while(1)
{
if((select(m_RecvSocket + 1,&readset,NULL,NULL,&tm)
<= 0))
{
//出错
break;
}
if(!FD_ISSET(m_RecvSocket,&readset)) continue;

ret = recv(m_RecvSocket,m_Buf,512 * 1024 - 1,0);
if(ret < 0)
{
//出错
break;
}
send(m_SendSocket,m_Buf,ret,0);
}
close(m_SendSocket);
close(m_RecvSocket);
}

/*
** 函数名称: SocketTrans
** 函数功能: 工作主函数,完成数据转发,新进程启动
** 传入参数: m_SendSocket : 发送套接字 m_RecvSocket : 接收套接字
** 传出参数: 无
** 引用函数: 无
** 返回值 : 无
** 备注 : 逆反完成全双工
*/
void SocketTrans()
{
struct sockaddr_in m_WorkAddr = {0};
int m_191Socket = 0;
int m_147socket = 0;
int m_WorkAddrLen = 0;

//开始任务执行
while(1)
{
//接受147的连接
m_WorkAddrLen = sizeof(struct sockaddr_in);
m_147socket = accept(m_ListenSocket,
(sockaddr*)&m_WorkAddr , &m_WorkAddrLen);

//检查套接字合法性
if(m_147socket < 0) continue;

//连接191
m_191Socket = GetConnectSocket(m_ConnectAddr,m_ConnectPort);
if(m_191Socket == NULL)
{
close(m_147socket);
continue;
}

int ret = fork();
if(ret < 0)
{
//建立新进程失败
printf("致命错误,无法建立新进程!\n");
fflush(stdout);
close(m_191Socket);
close(m_147socket);
break;
}
else if(ret == 0)
{
//关闭原来端口
close(m_ListenSocket);

//建立二次子进程,防止僵尸进程
ret = fork();
if(ret < 0)
{
close(m_191Socket);
close(m_147socket);
_exit(0);
}
else if(ret == 0)
{
//接收进程
TransSocket(m_191Socket,m_147socket);
_exit(0);
}
ret = fork();
if(ret < 0)
{
close(m_191Socket);
close(m_147socket);
_exit(0);
}
else if(ret == 0)
{
//发送进程
TransSocket(m_147socket,m_191Socket);
_exit(0);
}
close(m_191Socket);
close(m_147socket);
_exit(0);
}

//等待子线程结束
close(m_191Socket);
close(m_147socket);
waitpid(ret,NULL,0);
}
}

/*
** 函数名称: sig_usr
** 函数功能: 进程信号处理函数
** 传入参数: 无
** 传出参数: 无
** 引用函数: 无
** 返回值 : 无
** 备注 : 处理进程终止事件
*/
static void sig_usr(int signo)
{
close(m_ListenSocket);
if(m_MainId == getpid())
kill(0,SIGKILL);
exit(0);
}

static void sig_ign(int signo)
{
fprintf(stderr,"signal %d catched ,ignoring\n",signo);
}

int daemon_init()
{
pid_t pid;
if((pid=fork())<0){
return -1;
}else if(pid!=0){
exit(0);
}
setsid();
umask(0);
return 0;
}

/*
** 函数名称: main
** 函数功能: 进程主函数
** 传入参数: 无
** 传出参数: 无
** 引用函数: MakeFilePath,GetMyInitInfo,SocketTrans
** 返回值 : 无
** 备注 : 为客户接收进程主函数
*/
int main(int argc,char* argv[])
{
//检查参数合法性
if(argc != 4)
{
printf("格式:本地端口 目的地址 目的端口\n");
fflush(stdout);
return 0;
}

daemon_init();

//登记信号事件
signal(SIGTERM,sig_usr);
signal(SIGINT,sig_usr);
signal(SIGQUIT,sig_usr);
signal(SIGPIPE,sig_ign);
signal(SIGALRM,sig_ign);
signal(SIGQUIT,sig_ign);
signal(SIGFPE,sig_ign);
signal(SIGILL,sig_ign);
signal(SIGPIPE,sig_ign);
signal(SIGSEGV,sig_ign);
signal(SIGTRAP,sig_ign);
signal(SIGTSTP,sig_ign);

//取参数
strcpy(m_ConnectAddr,argv[2]);
strcpy(m_ConnectPort,argv[3]);

//获取侦听套接字
m_ListenSocket = GetListenSocket(atoi(argv[1]));
if(m_ListenSocket == 0)
{
printf("侦听端口[%s]失败!\n",argv[1]);
fflush(stdout);
return 0;
}

m_MainId = getpid();
//启动文件接收侦听线程
SocketTrans();
close(m_ListenSocket);
return 0;
}
  回复  更多评论
  
# re: 代理服务器代码 2008-10-21 02:19 聂文龙
#include "stdafx.h"
#include "Proxy.h"
#include < winsock2.h > //WINSOCKET API 2。0
#include < stdlib.h >
#include < stdio.h >
#include < string.h >


#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif


/////////////////////////////////////////////////////////////////////////////


#define HTTP "http://"
#define FTP "ftp://"
#define PROXYPORT 5001 //Proxy 端口
#define BUFSIZE 10240 //缓冲区大小


CWinApp theApp;


using namespace std;


UINT ProxyToServer(LPVOID pParam);
UINT UserToProxyThread(void *pParam);


strUCt SocketPair{
SOCKET user_proxy; //socket : 本地机器到PROXY 服务机
SOCKET proxy_server; //socket : PROXY 服务机到远程主机
BOOL IsUser_ProxyClosed; // 本地机器到PROXY 服务机状态
BOOL IsProxy_ServerClosed; // PROXY 服务机到远程主机状态
};


struct ProxyParam{
char Address[256]; // 远程主机地址
HANDLE User_SvrOK; // PROXY 服务机到远程主机的联结状态
SocketPair *pPair; // 维护一组SOCKET的指针
int Port; // 用来联结远程主机的端口
}; //这个结构用来PROXY SERVER与远程主机的信息交换.


SOCKET gListen_Socket; //用来侦听的SOCKET。


int StartServer() //启动服务
{
WSADATA wsaData;
sockaddr_in local;
SOCKET listen_socket;


if(::WSAStartup(0x202,&wsaData)!=0)
{printf("\nError in Startup session.\n");WSACleanup();return -1;};



local.sin_family=AF_INET;

local.sin_addr.s_addr=INADDR_ANY;
local.sin_port=htons(PROXYPORT);


listen_socket=socket(AF_INET,SOCK_STREAM,0);
if(listen_socket==INVALID_SOCKET)
{printf("\nError in New a Socket.");WSACleanup();return -2;}


if(::bind(listen_socket,(sockaddr *)&local,sizeof(local))!=0)
{printf("\n Error in Binding socket."); WSACleanup();return -3; };


if(::listen(listen_socket,5)!=0)
{printf("\n Error in Listen."); WSACleanup(); return -4;}
gListen_Socket=listen_socket;
AfxBeginThread(UserToProxyThread,NULL); //启动侦听
return 1;
}


int CloseServer() //关闭服务
{
closesocket(gListen_Socket);
WSACleanup();
return 1;
}
//分析接收到的字符,得到远程主机地址


int GetAddressAndPort( char * str, char *address, int * port)
{
char buf[BUFSIZE], command[512], proto[128], *p;
int j;
sscanf(str,"%s%s%s",command,buf,proto);
p=strstr(buf,HTTP);
//HTTP
if(p)
{
p+=strlen(HTTP);
for(int i=0;i< strlen(p);i++)
if( *(p+i)=='/') break;
*(p+i)=0;
strcpy(address,p);
p=strstr(str,HTTP);
for(int j=0;j< i+strlen(HTTP);j++)
*(p+j)=' '; //去掉远程主机名: GET http://www.njust.edu.cn/ HTTP1.1 == > GET / HTTP1.1
*port=80; //缺省的 http 端口
}
else
{//FTP, 不支持, 下面的代码可以省略.
p=strstr(buf,FTP);
if(!p) return 0;
p+=strlen(FTP);
for(int i=0;i< strlen(p);i++)
if( *(p+i)=='/') break; //Get The Remote Host
*(p+i)=0;
for(j=0;j< strlen(p);j++)
if(*(p+j)==':')
{*port=atoi(p+j+1); //Get The Port
*(p+j)=0;
}
else *port=21;



strcpy(address,p);
p=strstr(str,FTP);
for(j=0;j< i+strlen(FTP);j++)

*(p+j)=' ';
}
return 1;
}


// 取到本地的数据,发往远程主机
UINT UserToProxyThread(void *pParam)
{
char Buffer[BUFSIZE];
int Len;
sockaddr_in from;
SOCKET msg_socket;
int fromlen,retval;
SocketPair SPair;
ProxyParam ProxyP;
CWinThread *pChildThread;
fromlen=sizeof(from);
msg_socket=accept(gListen_Socket,(struct sockaddr*)&from,&fromlen);
AfxBeginThread(UserToProxyThread,pParam); //启动另一侦听.
if( msg_socket==INVALID_SOCKET)
{ printf( "\nError in accept "); return -5;}
//读客户的第一行数据


SPair.IsUser_ProxyClosed=FALSE;
SPair.IsProxy_ServerClosed=TRUE;
SPair.user_proxy=msg_socket;


retval=recv(SPair.user_proxy,Buffer,sizeof(Buffer),0);


if(retval==SOCKET_ERROR)
{ printf("\nError Recv");
if(SPair.IsUser_ProxyClosed==FALSE)
{closesocket(SPair.user_proxy);
SPair.IsUser_ProxyClosed=TRUE;
}
}
if(retval==0)
{printf("Client Close connection\n");
if(SPair.IsUser_ProxyClosed==FALSE)
{closesocket(SPair.user_proxy);
SPair.IsUser_ProxyClosed=TRUE;
}
}
Len=retval;
#ifdef _DEBUG


Buffer[Len]=0;
printf("\n Received %d bytes,data[%s]from client\n",retval,Buffer);
#endif
//
SPair.IsUser_ProxyClosed=FALSE;
SPair.IsProxy_ServerClosed=TRUE;
SPair.user_proxy=msg_socket;


ProxyP.pPair=&SPair;
ProxyP.User_SvrOK=CreateEvent(NULL,TRUE,FALSE,NULL);


GetAddressAndPort( Buffer,ProxyP.Address,&ProxyP.Port);


pChildThread=AfxBeginThread(ProxyToServer,(LPVOID)&ProxyP);

::WaitForSingleObject(ProxyP.User_SvrOK,60000); //等待联结
::CloseHandle(ProxyP.User_SvrOK);


while(SPair.IsProxy_ServerClosed ==FALSE && SPair.IsUser_ProxyClosed==FALSE)

{
retval=send(SPair.proxy_server,Buffer,Len,0);
if(retval==SOCKET_ERROR)
{ printf("\n send() failed:error%d\n",WSAGetLastError());
if(SPair.IsProxy_ServerClosed==FALSE)
{
closesocket(SPair.proxy_server);
SPair.IsProxy_ServerClosed=TRUE;
}
continue;
}
retval=recv(SPair.user_proxy,Buffer,sizeof(Buffer),0);


if(retval==SOCKET_ERROR)
{ printf("\nError Recv");
if(SPair.IsUser_ProxyClosed==FALSE)
{closesocket(SPair.user_proxy);
SPair.IsUser_ProxyClosed=TRUE;
}
continue;
}
if(retval==0)
{printf("Client Close connection\n");
if(SPair.IsUser_ProxyClosed==FALSE)
{closesocket(SPair.user_proxy);
SPair.IsUser_ProxyClosed=TRUE;
}
break;
}
Len=retval;
#ifdef _DEBUG
Buffer[Len]=0;
printf("\n Received %d bytes,data[%s]from client\n",retval,Buffer);
#endif


} //End While


if(SPair.IsProxy_ServerClosed==FALSE)
{
closesocket(SPair.proxy_server);
SPair.IsProxy_ServerClosed=TRUE;
}
if(SPair.IsUser_ProxyClosed==FALSE)
{closesocket(SPair.user_proxy);
SPair.IsUser_ProxyClosed=TRUE;
}
::WaitForSingleObject(pChildThread- >m_hThread,20000); //Should check the return value
return 0;
}


// 读取远程主机数据,并发往本地客户机
UINT ProxyToServer(LPVOID pParam){
ProxyParam * pPar=(ProxyParam*)pParam;
char Buffer[BUFSIZE];
char *server_name= "localhost";
unsigned short port ;
int retval,Len;
unsigned int addr;

int socket_type ;
struct sockaddr_in server;
struct hostent *hp;
SOCKET conn_socket;


socket_type = SOCK_STREAM;
server_name = pPar- >Address;
port = pPar- >Port;


if (isalpha(server_name[0])) { /* server address is a name */

hp = gethostbyname(server_name);
}
else { /* Convert nnn.nnn address to a usable one */
addr = inet_addr(server_name);
hp = gethostbyaddr((char *)&addr,4,AF_INET);
}
if (hp == NULL ) {
fprintf(stderr,"Client: Cannot resolve address [%s]: Error %d\n",
server_name,WSAGetLastError());
::SetEvent(pPar- >User_SvrOK);
return 0;
}


//
// Copy the resolved information into the sockaddr_in structure
//
memset(&server,0,sizeof(server));
memcpy(&(server.sin_addr),hp- >h_addr,hp- >h_length);
server.sin_family = hp- >h_addrtype;
server.sin_port = htons(port);


conn_socket = socket(AF_INET,socket_type,0); /* 打开一个 socket */
if (conn_socket < 0 ) {
fprintf(stderr,"Client: Error Opening socket: Error %d\n",
WSAGetLastError());
pPar- >pPair- >IsProxy_ServerClosed=TRUE;
::SetEvent(pPar- >User_SvrOK);
return -1;
}


#ifdef _DEBUG
printf("Client connecting to: %s\n",hp- >h_name);
#endif
if (connect(conn_socket,(struct sockaddr*)&server,sizeof(server))
== SOCKET_ERROR) {
fprintf(stderr,"connect() failed: %d\n",WSAGetLastError());
pPar- >pPair- >IsProxy_ServerClosed=TRUE;
::SetEvent(pPar- >User_SvrOK);
return -1;
}
pPar- >pPair- >proxy_server=conn_socket;
pPar- >pPair- >IsProxy_ServerClosed=FALSE;

::SetEvent(pPar- >User_SvrOK);
// cook up a string to send
while(!pPar- >pPair- >IsProxy_ServerClosed &&!pPar- >pPair- >IsUser_ProxyClosed)
{
retval = recv(conn_socket,Buffer,sizeof (Buffer),0 );
if (retval == SOCKET_ERROR ) {
fprintf(stderr,"recv() failed: error %d\n",WSAGetLastError());

closesocket(conn_socket);
pPar- >pPair- >IsProxy_ServerClosed=TRUE;
break;
}
Len=retval;
if (retval == 0) {
printf("Server closed connection\n");
closesocket(conn_socket);
pPar- >pPair- >IsProxy_ServerClosed=TRUE;
break;
}


retval = send(pPar- >pPair- >user_proxy,Buffer,Len,0);
if (retval == SOCKET_ERROR) {
fprintf(stderr,"send() failed: error %d\n",WSAGetLastError());
closesocket(pPar- >pPair- >user_proxy);
pPar- >pPair- >IsUser_ProxyClosed=TRUE;
break;
}
#ifdef _DEBUG
Buffer[Len]=0;
printf("Received %d bytes, data [%s] from server\n",retval,Buffer);
#endif
}
if(pPar- >pPair- >IsProxy_ServerClosed==FALSE)
{
closesocket(pPar- >pPair- >proxy_server);
pPar- >pPair- >IsProxy_ServerClosed=TRUE;
}
if(pPar- >pPair- >IsUser_ProxyClosed==FALSE)
{closesocket(pPar- >pPair- >user_proxy);
pPar- >pPair- >IsUser_ProxyClosed=TRUE;
}
return 1;
}





int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
{
int nRetCode = 0;


// 初始化SOCKET
if (!AfxWinInit(::GetModuleHandle(NULL), NULL, ::GetCommandLine(), 0))
{
// 错误处理
cerr < < _T("Fatal Error: MFC initialization failed") < < endl;
nRetCode = 1;

}
else
{
// 主程序开始.
StartServer();
while(1)
if(getchar()=='q') break;
CloseServer();
}


return nRetCode;
}
#ifdef _DEBUG
printf("Client connecting to: %s\n",hp- >h_name);
#endif
if (connect(conn_socket,(struct sockaddr*)&server,sizeof(server))
== SOCKET_ERROR) {
fprintf(stderr,"connect() failed: %d\n",WSAGetLastError());

pPar- >pPair- >IsProxy_ServerClosed=TRUE;
::SetEvent(pPar- >User_SvrOK);
return -1;
}
pPar- >pPair- >proxy_server=conn_socket;
pPar- >pPair- >IsProxy_ServerClosed=FALSE;
::SetEvent(pPar- >User_SvrOK);
// cook up a string to send
while(!pPar- >pPair- >IsProxy_ServerClosed &&!pPar- >pPair- >IsUser_ProxyClosed)
{
retval = recv(conn_socket,Buffer,sizeof (Buffer),0 );
if (retval == SOCKET_ERROR ) {
fprintf(stderr,"recv() failed: error %d\n",WSAGetLastError());
closesocket(conn_socket);
pPar- >pPair- >IsProxy_ServerClosed=TRUE;
break;
}
Len=retval;
if (retval == 0) {
printf("Server closed connection\n");
closesocket(conn_socket);
pPar- >pPair- >IsProxy_ServerClosed=TRUE;
break;
}


retval = send(pPar- >pPair- >user_proxy,Buffer,Len,0);
if (retval == SOCKET_ERROR) {
fprintf(stderr,"send() failed: error %d\n",WSAGetLastError());
closesocket(pPar- >pPair- >user_proxy);
pPar- >pPair- >IsUser_ProxyClosed=TRUE;
break;
}
#ifdef _DEBUG
Buffer[Len]=0;
printf("Received %d bytes, data [%s] from server\n",retval,Buffer);
#endif
}
if(pPar- >pPair- >IsProxy_ServerClosed==FALSE)

{
closesocket(pPar- >pPair- >proxy_server);
pPar- >pPair- >IsProxy_ServerClosed=TRUE;
}
if(pPar- >pPair- >IsUser_ProxyClosed==FALSE)
{closesocket(pPar- >pPair- >user_proxy);
pPar- >pPair- >IsUser_ProxyClosed=TRUE;
}
return 1;
}





int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
{
int nRetCode = 0;


// 初始化SOCKET
if (!AfxWinInit(::GetModuleHandle(NULL), NULL, ::GetCommandLine(), 0))
{
// 错误处理
cerr < < _T("Fatal Error: MFC initialization failed") < < endl;
nRetCode = 1;
}
else
{
// 主程序开始.
StartServer();
while(1)
if(getchar()=='q') break;
CloseServer();
}


return nRetCode;
}
  回复  更多评论
  
# re: 代理服务器代码 2008-10-21 02:22 聂文龙
打造自己的HTTP代理服务器
#include "stdafx.h"
#include "HTTPPROXY.h"
#define FD_NOEVENT 0
//
#define BACKUP 100
#define MAXDATALEN 65535
int HttpListenPort;
SOCKET HttpListenSock;
//
typedef struct _CLIENTINFO{
SOCKET clientsock;
SOCKET udpsock;
sockaddr_in clientsock_addr;
}CLIENTINFO,*LPCLIENTINFO;
CLIENTINFO HttpClientInfo;
//
typedef struct _SOCKINFO{
SOCKET sourcesock;
SOCKET destsock;
}SOCKINFO,*LPSOCKINFO;
SOCKINFO httpsockinfo;
//
extern long GetSocketEventId(SOCKET remotesock);
extern unsigned long GetLocalIp();
extern unsigned long GetDomainIp(char domainname[250]);
/*
long GetSocketEventId(SOCKET remotesock){
long EventId;
HANDLE hevent;
hevent=CreateEvent(NULL,0,0,0);
WSANETWORKEVENTS socket_events;
EventId=FD_NOEVENT;
if(WSAEventSelect(remotesock,hevent,FD_ACCEPT|FD_CONNECT|FD_
READ|FD_WRITE|FD_CLOSE)==SOCKET_ERROR) return EventId;
WSAEnumNetworkEvents(remotesock,hevent,&socket_events);
if(socket_events.lNetworkEvents!=0){
switch(socket_events.lNetworkEvents){
case FD_ACCEPT:EventId=FD_ACCEPT;break;
case FD_CONNECT:EventId=FD_CONNECT;break;
case FD_READ:EventId=FD_READ;break;
case FD_WRITE:EventId=FD_WRITE;break;
case FD_CLOSE:EventId=FD_CLOSE;break;
case FD_OOB:EventId=FD_OOB;break;
default:EventId=FD_NOEVENT;break;
}
}
else EventId=FD_NOEVENT;
return EventId;
}
//
unsigned long GetLocalIp()
{
char IP[MAX_PATH],*ip;
char pc_name[80];
struct in_addr in;
struct hostent *host;
WORD wVersionRequested;
WSADATA wsaData;
wVersionRequested=MAKEWORD(2,0);
ip=IP;
strcpy(ip,"Ip not get!");
if(WSAStartup(wVersionRequested,&wsaData)) return 0;
if(gethostname(pc_name,80)==SOCKET_ERROR){
WSACleanup();
return 0;
}
if(!(host=gethostbyname(pc_name))){
WSACleanup();
return 0;
}
in.s_addr=*((unsigned long *)host->h_addr_list[0]);
strcpy(ip,inet_ntoa(in));
WSACleanup();
return in.s_addr;
}
//
unsigned long GetDomainIp(char domainname[250])
{
char IP[MAX_PATH],*ip;
struct in_addr in;
struct hostent *host;
WORD wVersionRequested;
WSADATA wsaData;
wVersionRequested=MAKEWORD(2,0);
ip=IP;
strcpy(ip,"Ip not get!");
if(WSAStartup(wVersionRequested,&wsaData)) return 0;
if(!(host=gethostbyname(domainname))){
WSACleanup();
return 0;
}
in.s_addr=*((unsigned long *)host->h_addr_list[0]);
strcpy(ip,inet_ntoa(in));
WSACleanup();
return in.s_addr;
}
*/
//
//
UINT HttpReciveThread(LPVOID info){ //针对客户端的接收处理线程
LPSOCKINFO psockinfo;
SOCKET sourcesock,destsock;
char data[MAXDATALEN];
long eventid;
int datalen;
psockinfo=(LPSOCKINFO)info;
sourcesock=psockinfo->sourcesock;
destsock=psockinfo->destsock;
TRACE("deail recive thread ok!\r\n");
while(true){
eventid=GetSocketEventId(sourcesock);
switch(eventid){
case FD_CLOSE:
TRACE("s fdclosed\r\n");
closesocket(destsock);
return 1;
break;
default:break;
}
eventid=GetSocketEventId(destsock);
switch(eventid){
case FD_CLOSE:
closesocket(sourcesock);
TRACE("d fdclosed\r\n");
return 1;
break;
default:break;
}
datalen=recv(sourcesock,data,sizeof(data),0);
if(datalen==0){
closesocket(sourcesock);
closesocket(destsock);
TRACE("s fdclosed\r\n");
break;
}
if(datalen>0){
while(!send(destsock,data,datalen,0));
}
Sleep(1);
}
return 1;
}
//
UINT HttpSendThread(LPVOID info){ //针对远程端的接收处理线程
LPSOCKINFO psockinfo;
SOCKET sourcesock,destsock;
char data[MAXDATALEN];
long eventid;
int datalen;
psockinfo=(LPSOCKINFO)info;
sourcesock=psockinfo->sourcesock;
destsock=psockinfo->destsock;
TRACE("deail send thread ok!\r\n");
while(true){
eventid=GetSocketEventId(sourcesock);
switch(eventid){
case FD_CLOSE:
TRACE("s fdclosed\r\n");
closesocket(destsock);
return 1;
break;
default:break;
}
eventid=GetSocketEventId(destsock);
switch(eventid){
case FD_CLOSE:
closesocket(sourcesock);
TRACE("d fdclosed\r\n");
return 1;
break;
default:break;
}
datalen=recv(destsock,data,sizeof(data),0);
if(datalen==0){
closesocket(sourcesock);
closesocket(destsock);
TRACE("d fdclosed\r\n");
break;
}
if(datalen>0){
while(!send(sourcesock,data,datalen,0));
}
Sleep(1);
}
return 1;
}
//
//
UINT HttpProxyServerThread(LPVOID info){ //针对一次服务的线程
LPCLIENTINFO pclientinfo;
SOCKET connectsock,clientsock;
sockaddr_in remotesock_addr;
char data[MAXDATALEN],url[250],temp[250],httpurl[250],portnum[10];
int datalen,i,index_start,index_end,port;
CString HttpString,UrlString,PortString;
pclientinfo=(LPCLIENTINFO)info;
clientsock=pclientinfo->clientsock;
ZeroMemory((void *)data,sizeof(data));
datalen=recv(clientsock,data,sizeof(data),0);
if(datalen<=0){
closesocket(clientsock);
return 0;
}
HttpString.Format("%s",data);
UrlString=HttpString;
TRACE("get http string:\r\n");
TRACE(HttpString);
index_start=HttpString.Find("Host: ",0); //寻找url标记
if(index_start<=0){
closesocket(clientsock);
return 0;
}
index_end=HttpString.Find("\r\n",index_start);
if(index_end<=0){
closesocket(clientsock);
return 0;
}
UrlString=HttpString.Mid(index_start+6,index_end-index_start-6); //读取 url字符串
TRACE("\r\n get url:");
TRACE(UrlString);
wsprintf(url,"%s",UrlString);
strcpy(temp,url);
strcat(temp,":");
datalen=strlen(temp);
if(HttpString.Find("GET",0)==0){ //判断get命令,并处理
index_start=HttpString.Find(temp,0);
strcpy(httpurl,"http://");
if(index_start>0){
index_end=HttpString.Find("/",index_start);
if(index_end<=0){
closesocket(clientsock);
return 0;
}
PortString=HttpString.Mid(index_start+datalen,index_end-index_start-datalen);
port=atoi(PortString);
strcat(httpurl,temp);
itoa(port,portnum,sizeof(portnum));
strcat(httpurl,portnum);
strcat(httpurl,"/");
}
else{
port=80;
strcat(httpurl,url);
strcat(httpurl,"/");
}
TRACE("get http url:%s\r\n",httpurl);
HttpString.Replace(httpurl,"/");
HttpString.Replace("Proxy-","");
HttpString.Replace("HTTP/1.0","HTTP/1.1");
}
else if(HttpString.Find("CONNECT",0)==0){ //判断connect命令并处理
index_start=HttpString.Find(temp,0);
if(index_start>0){
index_end=HttpString.Find(" ",index_start);
if(index_end<=0){
closesocket(clientsock);
return 0;
}
PortString=HttpString.Mid(index_start+datalen,index_end-index_start-datalen);
port=atoi(PortString);
}
else{
closesocket(clientsock);
return 0;
}
}
TRACE("get new http string:\r\n");
TRACE(HttpString);
remotesock_addr.sin_family=AF_INET;
remotesock_addr.sin_port=htons(port);
remotesock_addr.sin_addr.S_un.S_addr=GetDomainIp(url);
connectsock=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
if(connect(connectsock,(const sockaddr *)&remotesock_addr,sizeof(remotesock_addr))==INVALID_SOCKET){ //连接远程主机
closesocket(clientsock);
return 0;
}
TRACE("\r\nconnect to remote ip ok\r\n");
ZeroMemory((void *)data,sizeof(data));
wsprintf(data,"%s",HttpString);
datalen=strlen(data);
if(HttpString.Find("CONNECT",0)<0) while(!send(connectsock,data,datalen,0));
else{
strcpy(data,"HTTP/1.0 200 Connection established\r\nProxy-agent: CHTTPPROXY V1.0 powered by shadow\r\n\r\n");
datalen=strlen(data);
while(!send(clientsock,data,datalen,0));
}
httpsockinfo.sourcesock=clientsock;
httpsockinfo.destsock=connectsock;
AfxBeginThread(HttpReciveThread,(LPVOID)&httpsockinfo); //抛出处理线程
AfxBeginThread(HttpSendThread,(LPVOID)&httpsockinfo); //
Sleep(100);
return 1;
}
//
UINT StartHttpProxy(LPVOID info){ //端口监听线程
SOCKET NewSock;
int socklen;
sockaddr_in serversock,remotesock_addr;
serversock.sin_family=AF_INET;
serversock.sin_addr.S_un.S_addr=INADDR_ANY;
serversock.sin_port=htons(HttpListenPort);
HttpListenSock=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
if(HttpListenSock==INVALID_SOCKET) return 0;
if(bind(HttpListenSock,(const sockaddr *)&serversock,
sizeof(serversock))==SOCKET_ERROR) return 0;
listen(HttpListenSock,BACKUP);
socklen=sizeof(remotesock_addr);
TRACE("start http proxy thread while\r\n");
while(true){
NewSock=accept(HttpListenSock,(sockaddr *)&remotesock_addr,&socklen);
TRACE("waitting ok...\r\n");
if(NewSock==INVALID_SOCKET){
Sleep(1);
continue;
}
ZeroMemory((void *)&HttpClientInfo,sizeof(CLIENTINFO));
HttpClientInfo.clientsock=NewSock;
HttpClientInfo.clientsock_addr=remotesock_addr;
TRACE("start proxy thread\r\n");
AfxBeginThread(HttpProxyServerThread,(LPVOID)&HttpClientInfo);
Sleep(100);
}
return 1;
}
//
CHTTPPROXY::CHTTPPROXY()
{
WSADATA WsaData;
WORD wsaVer;
wsaVer=MAKEWORD(2,0);
WsaStartupOk=false;
if(WSAStartup(wsaVer,&WsaData)!=SOCKET_ERROR) WsaStartupOk=true;
}

CHTTPPROXY::~CHTTPPROXY()
{
if(WsaStartupOk){
WSACleanup();
}
}

int CHTTPPROXY::StartProxy(int listenport)
{
HttpListenPort=listenport;
AfxBeginThread(StartHttpProxy,(LPVOID)NULL);
return 1;
}


/*=========================================================
FILE:HTTPPROXY.h
==========================================================*/
class CHTTPPROXY
{
public:
int StartProxy(int listenport);
bool WsaStartupOk;
CHTTPPROXY();
virtual ~CHTTPPROXY();

};

/*==================================================
FILE:stdafx.h
===================================================*/
#include
#include
#include
#include


注:不要忘了在link选项中添加wsock32.lib和ws2_32.lib,或在文件前部加上如下语句:
#paragma comment(lib,"wsock32.lib")
#paragma comment(lib,"ws2_32.lib")

本代码在win2k和vc6.0下编译成功~~
用法,把这几个文件添加到你的项目中,在WinMain()中添加如下代码:
CHTTPPROXY httpproxy;
httpproxy.StartProxy(7890);
有问题mailto me!


  回复  更多评论
  
# re: 代理服务器代码 2008-10-21 02:23 聂文龙
VC++6实现简单的代理服务器

本文转自CSDN的blog:http://blog.csdn.net/snaill/archive/2006/03/14/624437.aspx

#include "stdafx.h"
#include "Proxy.h"
#include < winsock2.h > //WINSOCKET API 2。0
#include < stdlib.h >
#include < stdio.h >
#include < string.h >

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////


#define HTTP "http://"
#define FTP "ftp://"
#define PROXYPORT 5001 //Proxy 端口
#define BUFSIZE 10240 //缓冲区大小


CWinApp theApp;

using namespace std;

UINT ProxyToServer(LPVOID pParam);
UINT UserToProxyThread(void *pParam);

struct SocketPair{
SOCKET user_proxy; //socket : 本地机器到PROXY 服务机
SOCKET proxy_server; //socket : PROXY 服务机到远程主机
BOOL IsUser_ProxyClosed; // 本地机器到PROXY 服务机状态
BOOL IsProxy_ServerClosed; // PROXY 服务机到远程主机状态
};


struct ProxyParam{
char Address[256]; // 远程主机地址
HANDLE User_SvrOK; // PROXY 服务机到远程主机的联结状态
SocketPair *pPair; // 维护一组SOCKET的指针
int Port; // 用来联结远程主机的端口
}; //这个结构用来PROXY SERVER与远程主机的信息交换.

SOCKET gListen_Socket; //用来侦听的SOCKET。

int StartServer() //启动服务
{
WSADATA wsaData;
sockaddr_in local;
SOCKET listen_socket;

if(::WSAStartup(0x202,&wsaData)!=0)
{printf("\nError in Startup session.\n");WSACleanup();return -1;};

local.sin_family=AF_INET;
local.sin_addr.s_addr=INADDR_ANY;
local.sin_port=htons(PROXYPORT);

listen_socket=socket(AF_INET,SOCK_STREAM,0);
if(listen_socket==INVALID_SOCKET)
{printf("\nError in New a Socket.");WSACleanup();return -2;}

if(::bind(listen_socket,(sockaddr *)&local,sizeof(local))!=0)
{printf("\n Error in Binding socket."); WSACleanup();return -3; };

if(::listen(listen_socket,5)!=0)
{printf("\n Error in Listen."); WSACleanup(); return -4;}
gListen_Socket=listen_socket;
AfxBeginThread(UserToProxyThread,NULL); //启动侦听
return 1;
}

int CloseServer() //关闭服务
{
closesocket(gListen_Socket);
WSACleanup();
return 1;
}
//分析接收到的字符,得到远程主机地址

int GetAddressAndPort( char * str, char *address, int * port)
{
char buf[BUFSIZE], command[512], proto[128], *p;
int j;
sscanf(str,"%s%s%s",command,buf,proto);
p=strstr(buf,HTTP);
//HTTP
if(p)
{
p+=strlen(HTTP);
for(int i=0;i< strlen(p);i++)
if( *(p+i)=='/') break;
*(p+i)=0;
strcpy(address,p);
p=strstr(str,HTTP);
for(int j=0;j< i+strlen(HTTP);j++)
*(p+j)=' '; //去掉远程主机名: GET http:/www.csdn.net/ HTTP1.1 == > GET / HTTP1.1
*port=80; //缺省的 http 端口
}
else
{//FTP, 不支持, 下面的代码可以省略.
p=strstr(buf,FTP);
if(!p) return 0;
p+=strlen(FTP);
for(int i=0;i< strlen(p);i++)
if( *(p+i)=='/') break; //Get The Remote Host
*(p+i)=0;
for(j=0;j< strlen(p);j++)
if(*(p+j)==':')
{*port=atoi(p+j+1); //Get The Port
*(p+j)=0;
}
else *port=21;

strcpy(address,p);
p=strstr(str,FTP);
for(j=0;j< i+strlen(FTP);j++)
*(p+j)=' ';
}
return 1;
}

// 取到本地的数据,发往远程主机
UINT UserToProxyThread(void *pParam)
{
char Buffer[BUFSIZE];
int Len;
sockaddr_in from;
SOCKET msg_socket;
int fromlen,retval;
SocketPair SPair;
ProxyParam ProxyP;
CWinThread *pChildThread;
fromlen=sizeof(from);
msg_socket=accept(gListen_Socket,(struct sockaddr*)&from,&fromlen);
AfxBeginThread(UserToProxyThread,pParam); //启动另一侦听.
if( msg_socket==INVALID_SOCKET)
{ printf( "\nError in accept "); return -5;}
//读客户的第一行数据

SPair.IsUser_ProxyClosed=FALSE;
SPair.IsProxy_ServerClosed=TRUE;
SPair.user_proxy=msg_socket;

retval=recv(SPair.user_proxy,Buffer,sizeof(Buffer),0);

if(retval==SOCKET_ERROR)
{ printf("\nError Recv");
if(SPair.IsUser_ProxyClosed==FALSE)
{closesocket(SPair.user_proxy);
SPair.IsUser_ProxyClosed=TRUE;
}
}
if(retval==0)
{printf("Client Close connection\n");
if(SPair.IsUser_ProxyClosed==FALSE)
{closesocket(SPair.user_proxy);
SPair.IsUser_ProxyClosed=TRUE;
}
}
Len=retval;
#ifdef _DEBUG

Buffer[Len]=0;
printf("\n Received %d bytes,data[%s]from client\n",retval,Buffer);
#endif
//
SPair.IsUser_ProxyClosed=FALSE;
SPair.IsProxy_ServerClosed=TRUE;
SPair.user_proxy=msg_socket;

ProxyP.pPair=&SPair;
ProxyP.User_SvrOK=CreateEvent(NULL,TRUE,FALSE,NULL);

GetAddressAndPort( Buffer,ProxyP.Address,&ProxyP.Port);

pChildThread=AfxBeginThread(ProxyToServer,(LPVOID)&ProxyP);
::WaitForSingleObject(ProxyP.User_SvrOK,60000); //等待联结
::CloseHandle(ProxyP.User_SvrOK);

while(SPair.IsProxy_ServerClosed ==FALSE && SPair.IsUser_ProxyClosed==FALSE)
{
retval=send(SPair.proxy_server,Buffer,Len,0);
if(retval==SOCKET_ERROR)
{ printf("\n send() failed:error%d\n",WSAGetLastError());
if(SPair.IsProxy_ServerClosed==FALSE)
{
closesocket(SPair.proxy_server);
SPair.IsProxy_ServerClosed=TRUE;
}
continue;
}
retval=recv(SPair.user_proxy,Buffer,sizeof(Buffer),0);

if(retval==SOCKET_ERROR)
{ printf("\nError Recv");
if(SPair.IsUser_ProxyClosed==FALSE)
{closesocket(SPair.user_proxy);
SPair.IsUser_ProxyClosed=TRUE;
}
continue;
}
if(retval==0)
{printf("Client Close connection\n");
if(SPair.IsUser_ProxyClosed==FALSE)
{closesocket(SPair.user_proxy);
SPair.IsUser_ProxyClosed=TRUE;
}
break;
}
Len=retval;
#ifdef _DEBUG
Buffer[Len]=0;
printf("\n Received %d bytes,data[%s]from client\n",retval,Buffer);
#endif

} //End While

if(SPair.IsProxy_ServerClosed==FALSE)
{
closesocket(SPair.proxy_server);
SPair.IsProxy_ServerClosed=TRUE;
}
if(SPair.IsUser_ProxyClosed==FALSE)
{closesocket(SPair.user_proxy);
SPair.IsUser_ProxyClosed=TRUE;
}
::WaitForSingleObject(pChildThread- >m_hThread,20000); //Should check the return value
return 0;
}
// 读取远程主机数据,并发往本地客户机
UINT ProxyToServer(LPVOID pParam){
ProxyParam * pPar=(ProxyParam*)pParam;
char Buffer[BUFSIZE];
char *server_name= "localhost";
unsigned short port ;
int retval,Len;
unsigned int addr;
int socket_type ;
struct sockaddr_in server;
struct hostent *hp;
SOCKET conn_socket;

socket_type = SOCK_STREAM;
server_name = pPar- >Address;
port = pPar- >Port;

if (isalpha(server_name[0])) { /* server address is a name */
hp = gethostbyname(server_name);
}
else { /* Convert nnn.nnn address to a usable one */
addr = inet_addr(server_name);
hp = gethostbyaddr((char *)&addr,4,AF_INET);
}
if (hp == NULL ) {
fprintf(stderr,"Client: Cannot resolve address [%s]: Error %d\n",
server_name,WSAGetLastError());
::SetEvent(pPar- >User_SvrOK);
return 0;
}

//
// Copy the resolved information into the sockaddr_in structure
//
memset(server,0,sizeof(server));
memcpy(&(server.sin_addr),hp- >h_addr,hp- >h_length);
server.sin_family = hp- >h_addrtype;
server.sin_port = htons(port);

conn_socket = socket(AF_INET,socket_type,0); /* 打开一个 socket */
if (conn_socket < 0 ) {
fprintf(stderr,"Client: Error Opening socket: Error %d\n",
WSAGetLastError());
pPar- >pPair- >IsProxy_ServerClosed=TRUE;
::SetEvent(pPar- >User_SvrOK);
return -1;
}
#ifdef _DEBUG
printf("Client connecting to: %s\n",hp- >h_name);
#endif
if (connect(conn_socket,(struct sockaddr*)server,sizeof(server))
== SOCKET_ERROR) {
fprintf(stderr,"connect() failed: %d\n",WSAGetLastError());
pPar- >pPair- >IsProxy_ServerClosed=TRUE;
::SetEvent(pPar- >User_SvrOK);
return -1;
}
pPar- >pPair- >proxy_server=conn_socket;
pPar- >pPair- >IsProxy_ServerClosed=FALSE;
::SetEvent(pPar- >User_SvrOK);
// cook up a string to send
while(!pPar- >pPair- >IsProxy_ServerClosed &&!pPar- >pPair- >IsUser_ProxyClosed)
{
retval = recv(conn_socket,Buffer,sizeof (Buffer),0 );
if (retval == SOCKET_ERROR ) {
fprintf(stderr,"recv() failed: error %d\n",WSAGetLastError());
closesocket(conn_socket);
pPar- >pPair- >IsProxy_ServerClosed=TRUE;
break;
}
Len=retval;
if (retval == 0) {
printf("Server closed connection\n");
closesocket(conn_socket);
pPar- >pPair- >IsProxy_ServerClosed=TRUE;
break;
}

retval = send(pPar- >pPair- >user_proxy,Buffer,Len,0);
if (retval == SOCKET_ERROR) {
fprintf(stderr,"send() failed: error %d\n",WSAGetLastError());
closesocket(pPar- >pPair- >user_proxy);
pPar- >pPair- >IsUser_ProxyClosed=TRUE;
break;
}
#ifdef _DEBUG
Buffer[Len]=0;
printf("Received %d bytes, data [%s] from server\n",retval,Buffer);
#endif
}
if(pPar- >pPair- >IsProxy_ServerClosed==FALSE)
{
closesocket(pPar- >pPair- >proxy_server);
pPar- >pPair- >IsProxy_ServerClosed=TRUE;
}
if(pPar- >pPair- >IsUser_ProxyClosed==FALSE)
{closesocket(pPar- >pPair- >user_proxy);
pPar- >pPair- >IsUser_ProxyClosed=TRUE;
}
return 1;
}



int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
{
int nRetCode = 0;

// 初始化SOCKET
if (!AfxWinInit(::GetModuleHandle(NULL), NULL, ::GetCommandLine(), 0))
{
// 错误处理
cerr < < _T("Fatal Error: MFC initialization failed") < < endl;
nRetCode = 1;
}
else
{
// 主程序开始.
StartServer();
while(1)
if(getchar()=='q') break;
CloseServer();
}

return nRetCode;
}   回复  更多评论
  
# re: 代理服务器代码 2008-10-21 02:25 聂文龙
通过Socket5代理服务器访问网络的问题
SOCKS5

Socks5版本的协议说明参考 RFC1928,RFC1929
下面简单地罗列程序实现,不涉及详细的协议规范。首先对于TCP连接,然后再讨论UDP传输。至于通过socks5的多播通讯,有兴趣可以参考D. Chouinard的文章。

1、TCP:

// 建立流套接字
SOCKET m_socTCP=socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

// 连接到代理服务器
int nRet = connect(m_socTCP,(SOCKADDR*)&m_saiProxy,sizeof(m_saiProxy));

// Step 1: 连接代理服务器成功后,马上开始和代理协商,协商报文如下,询问服务器,版本5,是需要验证(0x02)还是不需要验证(0x00)
  +------+-------------------+------------+
  |VER | Number of METHODS | METHODS |
  +------+-------------------+------------+
  | 0x05 | 0x02 (有两个方法) | 0x00 | 0x02|
  +------+-------------------+------------+
const char reqNego[4]={(char)0x05,(char)0x02,(char)0x00,(char)0x02};
nRet = send(m_socTCP,reqNego,4,0);

// Setp 2: 代理服务器将返回两个字节的协商结果,接收协商结果
fd_set fdread;FD_ZERO(&fdread);
FD_SET(m_socTCP,&fdread);
// Last param set to NULL for blocking operation. (struct timeval*)
if((nRet=select(0,&fdread,NULL,NULL,NULL))==SOCKET_ERROR){return NC_E_PROXY_SELECT_READ|WSAGetLastError();}
char resNego[2]={'\0'};
int nRcvd=0,nCount=0;
while(1)
{
if(FD_ISSET(m_socTCP,&fdread))
{
//接收sock[0]发送来的数据
do{
nRet = recv(m_socTCP, (char*)resNego+nRcvd, 2-nRcvd,0);
if(nRet==SOCKET_ERROR){return NC_E_PROXY_RECEIVE|WSAGetLastError();}
nRcvd += nRet;
}
while((nRcvd!=2)&&(++nCount<1000));
if(nRcvd==2) break;
}
if(nCount++>=2000){return NC_E_PROXY_RECEIVE|WSAGetLastError();}
}
if(resNego[0]!=0x05 || (resNego[1]!=0x00 && resNego[1]!=0x02)){return NC_E_PROXY_PROTOCOL_VERSION|WSAGetLastError();};

// Step 3: 根据协商结果判断是否需要验证用户,如果是0x02,则需要提供验证,验证部分参考RFC1929
if(resNego[1]==0x02)
{
// 需要密码验证
char reqAuth[513]={'\0'};
BYTE byLenUser = (BYTE)strlen(m_szProxyUserName);
BYTE byLenPswd = (BYTE)strlen(m_szProxyPassword);
reqAuth[0]=0x01;
reqAuth[1]=byLenUser;
sprintf(&reqAuth[2],"%s",m_szProxyUserName);
reqAuth[2+byLenUser]=byLenPswd;
sprintf(&reqAuth[3+byLenUser],"%s",m_szProxyPassword);
//Send authentication info
int len = (int)byLenUser + (int)byLenPswd + 3;
nRet=send(m_socTCP,(const char*)reqAuth,len,0);
if (nRet==SOCKET_ERROR){return NC_E_PROXY_SEND|WSAGetLastError();}
//Now : Response to the auth request
char resAuth[2]={'\0'};
int nRcvd=0,nCount=0;
do{
nRet = recv(m_socTCP,resAuth+nRcvd,2-nRcvd,0);
if(nRet==SOCKET_ERROR){return NC_E_PROXY_RECEIVE|WSAGetLastError();}
nRcvd += nRet;
}
while((nRcvd!=2)&&(++nCount<1000));
if(nCount>=1000){return NC_E_PROXY_RECEIVE|WSAGetLastError();}
if (resAuth[1]!=0) return NC_E_PROXY_AUTHORIZE;
// 密码验证通过了
}

// Step 4: 协商完成,开始发送连接远程服务器请求,请求报文格式如下:
  +----+-----+-------+------+----------+----------+
  |VER | CMD | RSV | ATYP | DST.ADDR | DST.PORT |
  +----+-----+-------+------+----------+----------+
  | 1 |  1 | 0x00 |  1 | Variable |   2   |
  +----+-----+-------+------+----------+----------+
// CMD==0x01 表示连接, ATYP==0x01表示采用IPV4格式地址,DST.ADDR是远程服务器地址,DST.PORT是远程服务器端口
// 如果需要接受外来连接,则需要在连接完成之后,发送CMD==0x02绑定请求,代理将为此请求绑定一个套接字接受外部连接
char reqSubNego[10]={(char)0x05,(char)0x01,(char)0x00,(char)0x01,(char)0x00,(char)0x00,(char)0x00,(char)0x00,(char)0x00,(char)0x00};
*(unsigned long*)&reqSubNego[4] =m_saiServerTCP.sin_addr.S_un.S_addr;
*(unsigned short*)&reqSubNego[8]=m_saiServerTCP.sin_port;
nRet=send(m_socTCP,(const char*)reqSubNego,10,0);
if (nRet==SOCKET_ERROR){return NC_E_PROXY_SEND|WSAGetLastError();}

// Step 5: 接收对请求的响应,响应包格式如下
  +----+-----+-------+------+----------+----------+
  |VER | REP | RSV | ATYP | BND.ADDR | BND.PORT |
  +----+-----+-------+------+----------+----------+
  | 1 | 1 | 0x00 | 1   | Variable |   2   |
  +----+-----+-------+------+----------+----------+
// VER 必须是0x05, REP==0x00表示成功,ATYP==0x01表示地址是IPV4地址,BND.ADDR 是代理为连接远程服务器绑定的地址,BND.PORT是这个套接字的端口
char resSubNego1[5]={'\0'};
if(FD_ISSET(m_socTCP,&fdread))
{
int nRcvd=0,nCount=0;
do{
nRet = recv(m_socTCP,resSubNego1+nRcvd,5-nRcvd,0);
if(nRet==SOCKET_ERROR){return NC_E_PROXY_RECEIVE|WSAGetLastError();}
nRcvd += nRet;
}
while((nRcvd!=5)&&(++nCount<1000));
if(nCount>=1000){return NC_E_PROXY_RECEIVE|WSAGetLastError();}
if(resSubNego1[0]!=0x05||resSubNego1[1]!=0x00){return NC_E_PROXY_PROTOCOL_VERSION_SUB|WSAGetLastError();};

switch(resSubNego1[3])
{
case 0x01:
{
// IP V4
char resSubNego2[6]={resSubNego1[4],0};
int nRet=-1;
if(FD_ISSET(m_socTCP,&fdread))
{
int nRcvd=0,nCount=0;
do{
int nRet = recv(m_socTCP,&resSubNego2[1]+nRcvd,5-nRcvd,0);
if(nRet==SOCKET_ERROR){return NC_E_PROXY_RECEIVE|WSAGetLastError();}
nRcvd += nRet;
}
while((nRcvd!=5)&&(++nCount<1000));
if(nCount>=1000){return NC_E_PROXY_RECEIVE|WSAGetLastError();}
}
// 得到代理绑定地址
unsigned long ulBINDAddr = *(unsigned long*)&resSubNego2; // SOCKS BIND ADDR
unsigned short usBINDPort = *(unsigned short*)&resSubNego2[4]; // SOCKS BIND PORT
m_saiProxyBindTCP.sin_addr.S_un.S_addr=ulBINDAddr;
m_saiProxyBindTCP.sin_port=usBINDPort;
// 得到本机绑定地址
int len = sizeof(m_saiHostTCP);
getsockname(m_socTCP,(SOCKADDR*)&m_saiHostTCP,&len);
}
break;
case 0x03:
{
// Domain name
int nLen = resSubNego1[4]+2;
char* presSubNego2 = new char[nLen];
if(FD_ISSET(m_socTCP,&fdread))
{
int nRet=0,nRcvd=0,nCount=0;
do{
nRet = recv(m_socTCP,presSubNego2+nRcvd,nLen-nRcvd,0);
if(nRet==SOCKET_ERROR){return NC_E_PROXY_RECEIVE|WSAGetLastError();}
nRcvd += nRet;
}
while((nRcvd!=nLen)&&(++nCount<1000));
if(nCount>=1000){return NC_E_PROXY_RECEIVE|WSAGetLastError();}
}
unsigned short usBINDPort = *(unsigned short*)(presSubNego2+nLen-2); // BIND PORT;
// 此时得到的是远程主机的Domain Name
delete[] presSubNego2; presSubNego2=NULL;
}
break;
case 0x04:
{
// IPV6
AfxMessageBox("该版本不支持IPV6";
}
break;
default:
break;
}

// 至此,连接已经建立。在此套接字上可进行数据的收发。
}

2、UDP

SOCKS V5提供了对UDP的支持,它通过在代理服务器和内网主机之间建立一个UDP中继的TCP连接,来辅助进行UDP数据包的收发。此连接有一个有效期,在此有效生命周期内,必须往代理发送UDP数据报确认连接有效,来维持此连接的有效性,否则,代理服务器超时,将会自动释放此连接的资源。
下面简单地罗列程序实现,不涉及详细的协议规范。

// 客户端为UDP中继建立一个相关的流套接字
SOCKET m_socClientTCP_UdpAssociate = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

// 连接代理服务器
int nRet=connect(m_socClientTCP_UdpAssociate,(SOCKADDR*)&saiProxy,sizeof(saiProxy));

// 连接成功,开始和代理服务器协商,首先发送版本标志,方法选择报文
const char reqNego[4]={(char)0x05,(char)0x02,(char)0x00,(char)0x02};
nRet = send(m_socClientTCP_UdpAssociate,reqNego,4,0);
if( nRet==SOCKET_ERROR
{
DWORD dwError = WSAGetLastError();
if (dwError!=WSAEWOULDBLOCK) return NCM_E_WM_CREATE_PROXYREQUESTFAILED;
}

// 接收协商的响应
fd_set fdread; FD_ZERO(&fdread);
FD_SET(m_socClientTCP_UdpAssociate,&fdread);
if((nRet=select(0,&fdread,NULL,NULL,NULL))==SOCKET_ERROR) return NCM_E_WM_CREATE_PROXYCONNECTFAILED;
char resNego[2]={0};
int nRcvd=0,nCount=0;
if(FD_ISSET(m_socClientTCP_UdpAssociate,&fdread))
{
nRcvd = recv(m_socClientTCP_UdpAssociate, (char*)resNego+nRcvd, 2,0);
if(nRcvd==SOCKET_ERROR) return NCM_E_WM_CREATE_PROXYCONNECTFAILED;
}
if(resNego[0]!=0x05 || (resNego[1]!=0x00 && resNego[1]!=0x02)) return NCM_E_WM_CREATE_PROXYCONNECTFAILED;

// 看是否需要密码验证
if(resNego[1]==0x02)
{
// 需要密码验证
char reqAuth[513]; memset(reqAuth,0,513);
BYTE byLenUser = (BYTE)strlen(m_szProxyUserName);
BYTE byLenPswd = (BYTE)strlen(m_szProxyPassword);
reqAuth[0]=0x01;
reqAuth[1]=byLenUser;
sprintf(&reqAuth[2],"%s",m_szProxyUserName);
reqAuth[2+byLenUser]=byLenPswd;
sprintf(&reqAuth[3+byLenUser],"%s",m_szProxyPassword);
//Send authentication info
int len = (int)byLenUser + (int)byLenPswd + 3;
int ret=send(m_socClientTCP_UdpAssociate,(const char*)reqAuth,len,0);
if (ret==SOCKET_ERROR) if (GetLastError()!=WSAEWOULDBLOCK) return NCM_E_WM_CREATE_PROXYREQUESTFAILED;

//Now : Response to the auth request
char resAuth[2]={'\0'};
int nRcvd=0,nCount=0;
do{
ret = recv(m_socClientTCP_UdpAssociate,resAuth+nRcvd,2-nRcvd,0);
if(ret==SOCKET_ERROR){return NC_E_PROXY_RECEIVE|WSAGetLastError();}
nRcvd += nRet;
}
while((nRcvd!=2)&&(++nCount<1000));
if(nCount>=1000){return NC_E_PROXY_RECEIVE}
if (resAuth[1]!=0) return NEM_E_WM_CREATE_PROXYAUTHFAILED;
// 密码验证通过了
}

// 开始发送向目标服务器的连接请求,其中DST.ADDR是目标服务器的地址,DST.PORT是目标服务器的UDP端口
char reqSubNego[10]={(char)0x05,(char)0x03,(char)0x00,(char)0x01,(char)0x00,(char)0x00,(char)0x00,(char)0x00,(char)0x00,(char)0x00};
*(unsigned long*)&reqSubNego[4] =saiServerUDP.sin_addr.S_un.S_addr; // cmd: DEST.addr
*(unsigned short*)&reqSubNego[8]=saiServerUDP.sin_port; // cmd: DEST.port in network octet order
nRet=send(m_socClientTCP_UdpAssociate,(const char*)reqSubNego,10,0);
if (nRet==SOCKET_ERROR) return NEM_E_WM_CREATE_PROXYREQFAILED;

// 接收响应信息
int nRecvCount = 0;
int nRecvBufferLen = 10;
char szRecvBuf[10];
nRet = 0;
if(FD_ISSET(m_socClientTCP_UdpAssociate,&fdread))
{
int nRcvd=0,nCount=0;
do{
nRet = recv(m_socClientTCP_UdpAssociate,(char*)szRecvBuf+nRcvd,10-nRcvd,0);
if(nRet==SOCKET_ERROR){return NC_E_PROXY_RECEIVE|WSAGetLastError();}
nRcvd += nRet;
}
while((nRcvd!=10)&&(++nCount<1000));
if(nCount>=1000){return NC_E_PROXY_RECEIVE;}
if (szRecvBuf[0]!=0x05||szRecvBuf[1]!=0x00){return NC_E_PROXY_PROTOCOL_VERSION_SUB;}
}
else
{
return NCM_E_WM_CREATE_PROXYREQUESTFAILED;
}

// 代理服务器绑定udp地址BND.ADR,一般代理服务器都是多宿主机器,因此这个绑定地址是局域网地址,代理服务器绑定udp端口BND.PORT
// m_ulProxyUDPAddr 代理绑定地址
// m_usUDPAssociatePort 代理绑定端口
memmove(&m_ulProxyUDPAddr,&szRecvBuf[4],4);
memmove(&m_usUDPAssociatePort,&szRecvBuf[8],2);

m_bUDPAssociated = TRUE;
// 至此,得到了代理绑定的地址和端口,客户端就可以通过它来收发UDP数据报了


// 客户端收发实例
// 首先创建数据报套接字,绑定套接字,得到本地数据报套接字地址,端口
SOCKET m_socClientUDP=WSASocket(AF_INET,SOCK_DGRAM,0,NULL,0,WSA_FLAG_OVERLAPPED);
SOCKADDR_IN saiLocal;
memset(&saiLocal,0,sizeof(saiLocal));
saiLocal.sin_family = AF_INET;
saiLocal.sin_port = 0;
saiLocal.sin_addr.S_un.S_addr = INADDR_ANY;
// 绑定本地udp套接字地址,地址+端口由系统决定
if (bind(m_socClientUDP, (SOCKADDR *)&saiLocal, sizeof(saiLocal) == SOCKET_ERROR)
getsockname(m_socClientUDP, (sockaddr*)&saiLocal, &len);
// m_ulHostAddr 本机绑定地址
// m_usHostPortUdp 本机绑定端口
m_ulHostAddr = saiLocal.sin_addr.S_un.S_addr;
m_usHostPortUdp = saiLocal.sin_port;

// 按照格式,发送数据
SOCKADDR_IN saiProxy;
memset(&saiProxy,0,sizeof(saiProxy));
saiProxy.sin_family = AF_INET;
saiProxy.sin_addr.S_un.S_addr = m_ulProxyUDPAddr; // 代理绑定的udp地址
saiProxy.sin_port = m_usUDPAssociatePort; // 代理绑定的udp端口

// 每个UDP包必须携带如下所述的头:
+----+------+------+----------+----------+----------+
|RSV | FRAG | ATYP | DST.ADDR | DST.PORT | DATA |
+----+------+------+----------+----------+----------+
| 2 | 1 | 1 | Variable | 2 | Variable |
+----+------+------+----------+----------+----------+
// 其中 ATYP==0x01 表示采用 IPV4 地址,那么头长度就是10,DST.ADDR并不是服务器地址,而是本机绑定地址,DST.PORT是本机绑定端口
char buf[10+2]={'0x00','0x00','0x00','0x01','0xff'};
memmove(&buf[4],&m_ulHostAddr,4);
*(unsigned short*)&buf[8]=m_usHostPortUDP;
int nRet = sendto(m_socClientUDP,buf,12,0,(SOCKADDR*)&saiProxy,sizeof(saiProxy));

// 接收数据
int nLen = sizeof(saiProxy);
char buf=new char[MAX_UDPLEN];
nRet = recvfrom(m_socClientUDP,buf,MAX_UDPLEN,0,(SOCKADDR *)&saiProxy,&nLen);
if(nRet==SOCKET_ERROR) return SOCKET_ERROR;
BYTE flag=0xff;
if(memcmp(&buf[0],&flag,1)==0) return SOCKET_ERROR;
BYTE byProxyHead[20];
byProxyHead[0]=byProxyHead[1]=byProxyHead[2]=0;
byProxyHead[3]=1;
*(unsigned long*)&byProxyHead[4] = saiServerUDP.sin_addr.S_un.S_addr;
*(unsigned short*)&byProxyHead[8] = saiServerUDP.sin_port;
byProxyHead[10]=byProxyHead[11]=byProxyHead[12]=0;
byProxyHead[13]=1;
*(unsigned long*)&byProxyHead[14] = m_ulHostAddr;
*(unsigned short*)&byProxyHead[18] = m_usHostPortUdp;

int i=0;
BOOL bIsForMe=FALSE;
if(memcmp(&byProxyHead[0],&buf[i],4)==0)
{
unsigned long ulRetAddr = *(unsigned long*)&buf[i+4];
if(ulRetAddr==m_ulHostAddr)
{
unsigned short usRetPort = ntohs((unsigned short)(*(unsigned short*)&buf[i+8]));
if(usRetPort==m_usHostPortUdp)
{
bIsForMe=TRUE;
}
}
i+=10;
}
// 客户端收发结束


// 服务器端发送实例
// m_ulProxyUDPAddr 代理绑定地址
// m_usUDPAssociatePort 代理绑定端口
// m_ulHostAddr 本机绑定地址
// m_usHostPortUdp 本机绑定端口
// 客户端必须把上面的m_ulProxyUDPAddr,m_usUDPAssociatePort,m_ulHostAddr,m_usHostPortUdp告知服务器,服务器通过这两个套接字进行数据的收发

// 服务器创建数据报套接字
SOCKET m_socUDP=WSASocket(AF_INET,SOCK_DGRAM,0,NULL,0,WSA_FLAG_OVERLAPPED);

// 代理的udp中继地址
SOCKADDR_IN saiClient;
saiClient.sin_family = AF_INET;
saiClient.sin_addr.S_un.S_addr = m_ulProxyUDPAddr;
saiClient.sin_port = m_usUDPAssociatePort;
// 如果远程目标在代理服务器后面,透过代理,指定远程目标的socks信息,参照RFC1928
char buffer[10]={'\0'};
buffer[0]=buffer[1]=buffer[2]=0;
buffer[3]=1; // No Fragment, It's a dependent udp, no need for socks server to arrange udp fragments

// 目标机器的地址端口,透过代理后发向这里
*(int*)&buffer[4]=m_ulHostAddr;
*(unsigned short*)&buffer[8]=m_usHostPortUdp;
BYTE buf[DATA_BUFSIZE]={'\0'};
memmove(&buf[10],&szSendbuf[0],dwLength);
memmove(&buf[0],&buffer[0],10);
int nSent = sendto(m_socUDP, (const char*)&buf[0], dwLength+10, 0, (SOCKADDR*)&saiClient,sizeof(saiClient));
// 服务器端发送结束  回复  更多评论
  
# re: 代理服务器代码 2008-10-21 02:29 聂文龙
关于通过http代理访问Internet
最近在网上查了一点关于通过Socket代理或者http代理访问internet的资料,国内的资料比较少,查到了一点英文资料,觉得讲得还不错。
When an HTTP connection is made through a proxy server the client (usually the browser) sends the request to the proxy. The proxy opens the connection to the destination, sends the request, receives the response and sends it back to the client. The HTTP protocol specifies a request method called CONNECT. The CONNECT method can be used by the client to inform the proxy server that a connection to some host on some port is required. The proxy server, if allows such connections, tries to connect to the destination address specified in the request header. If it the operation fails it sends back to the client a negative HTTP response and close the connection. If the operation succeeded then send back an HTTP positive response and the connection is consider established. After that, the proxy does not care what data is transferred between client requesting the connection and the destination. It just forwards data in both ways acting as a tunnel.

About the protocol
We are interested in CONNECT method from the HTTP protocol. After the applications opens a connection with the proxy server it must send the connect request in the form of an HTTP request:

CONNECT <destination_address>:<destination_port> <http_version><CR><LF><header_line><CR><LF><header_line><CR><LF>...<header_line><CR><LF><CR><LF>The proxy server process the request and try to make a connection to <destionation_address>:<destination_port>.

The proxy server sends back an HTTP response in the form:

<http_version> <code> <message><CR><LF><header_line><CR><LF><header_line><CR><LF>...<header_line><CR><LF><CR><LF>If it is a positive response (code=200) then after the empty line the proxy begins to acts as a tunnel and forwards data. If it is a negative response (code!=200) then connection is closed after the empty line.

The HTTPTunneling application
The application act as specified in a configuration file. An entry in the configuration file locks like this:

<Source port> <Destination address> <Destination port> <Proxy address> <Proxy port>If the application is running and an entry in the configuration files changes, the application automatically updates itself.

For every entry in the configuration file the application creates a port listener. This is a thread that opens a socket on <Source port> and waits for connection. When a request arrives on that port it tries to open a tunnel to the <Destination address>:< port>. If the <Proxy address> and <Proxy port> are missing, a direct connection is made. If the field are present it opens a connection to the proxy and sends a CONNECT request using the method specified above. The tunnel construction is made in a separate thread to let the port listener to accept immediatelly new connections. After the connection is established a tunnel object is constructed based on the opened sockets, sockets are marked as non-blocking and the object is passed to manager object. The thread that has created the tunnel is destroyed. Data transfer is made on a single thread. When one of the ends closes the connection the tunnel closes the other and the tunnel is marked as inactive. The manager finds the tunnel inactive and removes it from the list of active tunnels. By default the application generates log information in HTTPTunneling.log file. This file can be consulted to find wrong application behaviour.
  回复  更多评论
  
# re: 代理服务器代码 2008-10-21 11:35 聂文龙
[转载]C语言写的Linux平台socks5代理程序
C语言写的Linux平台socks5代理程序

信息来源:邪恶八进制信息安全团队(www.eviloctal.com)

前几天MSN老上不去,我还以为是公司做了防火墙限制。于是把去年这个时候写得一个代理程序改了改,拿出来用。结果发现MSN是因为微软的问题,鄙视啊……
因为写得比较急,这个只支持TCP代理,UDP的我没写,因为MSN用不上。这个代码可以随意修改分发,不过最好能给我一份。

这是头文件:
///////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Socks5代理头文件,定义协议相关数据包结构
// 版本 0.1,作者 云舒
// 2007年1月9日凌晨1点15分,GF回家已经11天了。
// 2008年1月25日修改,今年GF一直在我身边,哈哈
//
// 参考:
// http://www.rfc-editor.org/rfc/rfc1928.txt">http://www.rfc-editor.org/rfc/rfc1928.txt
// http://www.rfc-editor.org/rfc/rfc1929.txt">http://www.rfc-editor.org/rfc/rfc1929.txt
///////////////////////////////////////////////////////////////////////////////////////////////////////////////

#ifndef SOCKS5_H
#define SOCKS5_H

#define VERSION 0x05
#define CONNECT 0x01
#define IPV4 0x01
#define DOMAIN 0x03
#define IPV6 0x04

typedef struct _method_select_response // 协商方法服务器响应
{
char version; // 服务器支持的Socks版本,0x04或者0x05
char select_method;// 服务器选择的方法,0x00为匿名,0x02为密码认证
} METHOD_SELECT_RESPONSE;

typedef struct _method_select_request // 协商方法服务端请求
{
char version; // 客户端支持的版本,0x04或者0x05
char number_methods; // 客户端支持的方法的数量
char methods[255]; // 客户端支持的方法类型,最多255个,0x00为匿名,0x02为密码认证
} METHOD_SELECT_REQUEST;

typedef struct _AUTH_RESPONSE // 用户密码认证服务端响应
{
char version;// 版本,此处恒定为0x01
char result;// 服务端认证结果,0x00为成功,其他均为失败
} AUTH_RESPONSE;

typedef struct _AUTH_REQUEST //用户密码认证客户端请求
{
char version; // 版本,此处恒定为0x01
char name_len; // 第三个字段用户名的长度,一个字节,最长为0xff
char name[255]; // 用户名
char pwd_len;// 第四个字段密码的长度,一个字节,最长为0xff
char pwd[255]; // 密码
} AUTH_REQUEST;

typedef struct _SOCKS5_RESPONSE // 连接真实主机,Socks代理服务器响应
{
char version; // 服务器支持的Socks版本,0x04或者0x05
char reply; // 代理服务器连接真实主机的结果,0x00成功
char reserved; // 保留位,恒定位0x00
char address_type; // Socks代理服务器绑定的地址类型,IP V4为0x01,IP V6为0x04,域名为0x03
char address_port[1]; // 如果address_type为域名,此处第一字节为域名长度,其后为域名本身,无0字符结尾,域名后为Socks代理服务器绑定端口
}SOCKS5_RESPONSE;

typedef struct _SOCKS5_REQUEST // 客户端请求连接真实主机
{
char version; // 客户端支持的Socks版本,0x04或者0x05
char cmd; // 客户端命令,CONNECT为0x01,BIND为0x02,UDP为0x03,一般为0x01
char reserved; // 保留位,恒定位0x00
char address_type; // 客户端请求的真实主机的地址类型,IP V4为0x00,IP V6为0x04,域名为 0x03 char address_port[1]; // 如果address_type为域名,此处第一字节为域名长度,其后为域名本身,无0字符结尾,域名后为真实主机绑定端口

}SOCKS5_REQUEST;
#endif
主程序来了:
///////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Socks5程序,只支持TCP代理
// 版本 0.1,作者 云舒
// 2007年1月9日凌晨1点15分,GF回家已经11天了。
// 2008年1月25日修改,今年GF一直在我身边,哈哈
//
// 参考:
// http://www.rfc-editor.org/rfc/rfc1928.txt">http://www.rfc-editor.org/rfc/rfc1928.txt
// http://www.rfc-editor.org/rfc/rfc1929.txt">http://www.rfc-editor.org/rfc/rfc1929.txt
//编译:
// gcc -o socks5 -O2 Socks5.c -lpthread( RedHat AS5测试 )
///////////////////////////////////////////////////////////////////////////////////////////////////////////////

#include <stdio.h>
#include <netinet/in.h>
#include <netdb.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <signal.h>
#include <pthread.h>
#include <errno.h>
#include <string.h>
#include <sys/socket.h>
#include <arpa/inet.h>

#include "Socks5.h"

#define MAX_USER 10
#define BUFF_SIZE 1024

#define AUTH_CODE 0x02

#define TIME_OUT 6000000

#define USER_NAME "yunshu"
#define PASS_WORD "ph4nt0m"

// Select auth method, return 0 if success, -1 if failed
int SelectMethod( int sock )
{
char recv_buffer[BUFF_SIZE] = { 0 };
char reply_buffer[2] = { 0 };

METHOD_SELECT_REQUEST *method_request;
METHOD_SELECT_RESPONSE *method_response;

// recv METHOD_SELECT_REQUEST
int ret = recv( sock, recv_buffer, BUFF_SIZE, 0 );
if( ret <= 0 )
{
perror( "recv error" );
close( sock );

return -1;
}

//printf( "SelectMethod: recv %d bytes\n", ret );

// if client request a wrong version or a wrong number_method
method_request = (METHOD_SELECT_REQUEST *)recv_buffer;
method_response = (METHOD_SELECT_RESPONSE *)reply_buffer;

method_response->version = VERSION;

// if not socks5
if( (int)method_request->version != VERSION )
{
method_response->select_method = 0xff;

send( sock, method_response, sizeof(METHOD_SELECT_RESPONSE), 0 );
close( sock );

return -1;
}

method_response->select_method = AUTH_CODE;
if( -1 == send( sock, method_response, sizeof(METHOD_SELECT_RESPONSE), 0 ) )
{
close( sock );
return -1;
}

return 0;
}

// test password, return 0 for success.
int AuthPassword( int sock )
{
char recv_buffer[BUFF_SIZE] = { 0 };
char reply_buffer[BUFF_SIZE] = { 0 };

AUTH_REQUEST *auth_request;
AUTH_RESPONSE *auth_response;

// auth username and password
int ret = recv( sock, recv_buffer, BUFF_SIZE, 0 );
if( ret <= 0 )
{
perror( "recv username and password error" );
close( sock );
return -1;
}
//printf( "AuthPass: recv %d bytes\n", ret );

auth_request = (AUTH_REQUEST *)recv_buffer;

memset( reply_buffer, 0, BUFF_SIZE );
auth_response = (AUTH_RESPONSE *)reply_buffer;
auth_response->version = 0x01;

char recv_name[256] = { 0 };
char recv_pass[256] = { 0 };

// auth_request->name_len is a char, max number is 0xff
char pwd_str[2] = { 0 };
strncpy( pwd_str, auth_request->name + auth_request->name_len, 1 );
int pwd_len = (int)pwd_str[0];

strncpy( recv_name, auth_request->name, auth_request->name_len );
strncpy( recv_pass, auth_request->name + auth_request->name_len + sizeof(auth_request->pwd_len), pwd_len );

//printf( "username: %s\npassword: %s\n", recv_name, recv_pass );
// check username and password
if( (strncmp( recv_name, USER_NAME, strlen(USER_NAME) ) == 0) &&
(strncmp( recv_pass, PASS_WORD, strlen(PASS_WORD) ) == 0)
)
{
auth_response->result = 0x00;
if( -1 == send( sock, auth_response, sizeof(AUTH_RESPONSE), 0 ) )
{
close( sock );
return -1;
}
else
{
return 0;
}
}
else
{
auth_response->result = 0x01;
send( sock, auth_response, sizeof(AUTH_RESPONSE), 0 );

close( sock );
return -1;
}
}

// parse command, and try to connect real server.
// return socket for success, -1 for failed.
int ParseCommand( int sock )
{
char recv_buffer[BUFF_SIZE] = { 0 };
char reply_buffer[BUFF_SIZE] = { 0 };

SOCKS5_REQUEST *socks5_request;
SOCKS5_RESPONSE *socks5_response;

// recv command
int ret = recv( sock, recv_buffer, BUFF_SIZE, 0 );
if( ret <= 0 )
{
perror( "recv connect command error" );

close( sock );
return -1;
}

socks5_request = (SOCKS5_REQUEST *)recv_buffer;
if( (socks5_request->version != VERSION) || (socks5_request->cmd != CONNECT) ||
(socks5_request->address_type == IPV6) )
{
//printf( "connect command error.\n" );
close( sock );
return -1;
}

// begain process connect request
struct sockaddr_in sin;

memset( (void *)&sin, 0, sizeof(struct sockaddr_in) );
sin.sin_family = AF_INET;

// get real server&#39;s ip address
if( socks5_request->address_type == IPV4 )
{
memcpy( &sin.sin_addr.s_addr, &socks5_request->address_type + sizeof(socks5_request->address_type) , 4 );
memcpy( &sin.sin_port, &socks5_request->address_type + sizeof(socks5_request->address_type) + 4, 2 );

//printf( "Real Server: %s %d\n", inet_ntoa( sin.sin_addr ), ntohs( sin.sin_port ) );
}
else if( socks5_request->address_type == DOMAIN )
{
char domain_length = *(&socks5_request->address_type + sizeof(socks5_request->address_type));
char target_domain[ 256] = { 0 };

strncpy( target_domain, &socks5_request->address_type + 2, (unsigned int)domain_length );

//printf( "target: %s\n", target_domain );

struct hostent *phost = gethostbyname( target_domain );
if( phost == NULL )
{
//printf( "Resolve %s error!\n" , target_domain );

close( sock );
return -1;
}
memcpy( &sin.sin_addr , phost->h_addr_list[0] , phost->h_length );

memcpy( &sin.sin_port, &socks5_request->address_type + sizeof(socks5_request->address_type) +
sizeof(domain_length) + domain_length, 2 );
}

// try to connect to real server
int real_server_sock = socket( AF_INET, SOCK_STREAM, 0 );
if( real_server_sock < 0 )
{
perror( "Socket creation failed\n");

close( sock );
return -1;
}

memset( reply_buffer, 0, sizeof(BUFF_SIZE) );

socks5_response = (SOCKS5_RESPONSE *)reply_buffer;

socks5_response->version = VERSION;
socks5_response->reserved = 0x00;
socks5_response->address_type = 0x01;
memset( socks5_response + 4, 0 , 6 );

ret = connect( real_server_sock, (struct sockaddr *)&sin, sizeof(struct sockaddr_in) );
if( ret == 0 )
{
socks5_response->reply = 0x00;
if( -1 == send( sock, socks5_response, 10, 0 ) )
{
close( sock );

return -1;
}
}
else
{
perror( "Connect to real server error" );
socks5_response->reply = 0x01;
send( sock, socks5_response, 10, 0 );

close( sock );
return -1;
}

return real_server_sock;
}

int ForwardData( int sock, int real_server_sock )
{
char recv_buffer[BUFF_SIZE] = { 0 };

fd_set fd_read;
struct timeval time_out;

time_out.tv_sec = 0;
time_out.tv_usec = TIME_OUT;

int ret = 0;

while( 1 )
{
FD_ZERO( &fd_read );
FD_SET( sock, &fd_read );
FD_SET( real_server_sock, &fd_read );

ret = select( (sock > real_server_sock ? sock : real_server_sock) + 1, &fd_read, NULL, NULL, &time_out );
if( -1 == ret )
{
perror( "select socket error" );
break;
}
else if( 0 == ret )
{
//perror( "select time out" );
continue;
}

//printf( "[DEBUG] testing readable!\n" );
if( FD_ISSET(sock, &fd_read) )
{
//printf( "client can read!\n" );
memset( recv_buffer, 0, BUFF_SIZE );
ret = recv( sock, recv_buffer, BUFF_SIZE, 0 );
if( ret > 0 )
{
//printf( "%s", recv_buffer );
//printf( "recv %d bytes from client.\n", ret );
ret = send( real_server_sock, recv_buffer, ret, 0 );
if( ret == -1 )
{
perror( "send data to real server error" );
break;
}
//printf( "send %d bytes to client!\n", ret );
}
else if( ret == 0 )
{
//printf( "client close socket.\n" );
break;
}
else
{
//perror( "recv from client error" );
break;
}
}

else if( FD_ISSET(real_server_sock, &fd_read) )
{
//printf( "real server can read!\n" );
memset( recv_buffer, 0, BUFF_SIZE );
ret = recv( real_server_sock, recv_buffer, BUFF_SIZE, 0 );
if( ret > 0 )
{
//printf( "%s", recv_buffer );
//printf( "recv %d bytes from real server.\n", ret );
ret = send( sock, recv_buffer, ret, 0 );
if( ret == -1 )
{
perror( "send data to client error" );
break;
}
}
else if( ret == 0 )
{
//printf( "real server close socket.\n" );
break;
}
else
{
perror( "recv from real server error" );
break;
}
}
}

return 0;
}

int Socks5( void *client_sock )
{
int sock = *(int *)client_sock;

if( SelectMethod( sock ) == -1 )
{
//printf( "socks version error\n" );
return -1;
}

if( AuthPassword( sock ) == -1 )
{
//printf( "auth password error\n" );
return -1;
}

int real_server_sock = ParseCommand( sock );
if( real_server_sock == -1 )
{
//printf( "parse command error.\n" );
return -1;
}

ForwardData( sock, real_server_sock );

close( sock );
close( real_server_sock );

return 0;
}

int main( int argc, char *argv[] )
{
if( argc != 2 )
{
printf( "Socks5 proxy for test,code by YunShu\n" );
printf( "Usage: %s <proxy_port>\n", argv[0] );
printf( "Options:\n" );
printf( " <proxy_port> ---which port of this proxy server will listen.\n" );

return 1;
}

struct sockaddr_in sin;

memset( (void *)&sin, 0, sizeof( struct sockaddr_in) );
sin.sin_family = AF_INET;
sin.sin_port = htons( atoi(argv[1]) );
sin.sin_addr.s_addr = htonl(INADDR_ANY);

int listen_sock = socket( AF_INET, SOCK_STREAM, 0 );
if( listen_sock < 0 )
{
perror( "Socket creation failed\n");
return -1;
}

int opt = SO_REUSEADDR;
setsockopt( listen_sock, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt) );

if( bind( listen_sock, (struct sockaddr*)&sin, sizeof(struct sockaddr_in) ) < 0 )
{
perror( "Bind error" );
return -1;
}

if( listen( listen_sock, MAX_USER ) < 0 )
{
perror( "Listen error" );
return -1;
}

struct sockaddr_in cin;
int client_sock;
int client_len = sizeof( struct sockaddr_in );

while( client_sock = accept( listen_sock, (struct sockaddr *)&cin, (socklen_t *)&client_len ) )
{
printf( "Connected from %s, processing......\n", inet_ntoa( cin.sin_addr ) );

pthread_t work_thread;
if( pthread_create( &work_thread, NULL, (void *)Socks5, (void *)&client_sock ) )
{
perror( "Create thread error..." );
close( client_sock );
}
else
{
pthread_detach( work_thread );
}
}
}   回复  更多评论
  
# re: 代理服务器代码 2012-05-08 23:16 迷失
聊天记录  回复  更多评论
  

只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理