找回密码
 立即注册→加入我们

QQ登录

只需一步,快速开始

搜索
热搜: 下载 VB C 实现 编写
查看: 5032|回复: 7

【TCPIP】借助Winsock编写HTTP转发程序(虽然没啥用但是有代码)

[复制链接]
发表于 2014-3-11 18:42:52 | 显示全部楼层 |阅读模式

欢迎访问技术宅的结界,请注册或者登录吧。

您需要 登录 才可以下载或查看,没有账号?立即注册→加入我们

×
我来说一下浏览器是怎么上网的。首先,网站的服务器程序开启之后,它会通过TCPIP协议监听80端口并等待连接。
然后,用户通过浏览器上网,浏览器会尝试连接到服务器,连接完成以后,浏览器按照HTTP协议发送一个数据包(HTTP请求)。
服务器接收到浏览器的数据包以后,回复一个数据包给浏览器。这个数据包包括了一个HTTP头和一些其余的数据(比如网页文件、图片等)。
浏览器接收到服务器的数据包以后,显示出网页的内容。这就是浏览器的运行方式。

虽然HTTP协议我们可以自己从网上找到学习的资料,但是如果我们能自己截获这些数据包,我们就能更容易地学到它的原理。因此我写了一个转发程序。
程序运行的原理:通过TCP/IP协议监听80端口。当有浏览器连接到它的时候,它就去连接一个别的、我们指定了的网页(比如www.baidu.com
然后把浏览器的数据包转发到网站服务器(百度)(顺带再把数据包发一份到stdout)。然后百度的服务器就会回复一个数据包,我这个转发器就截获百度的数据包并转发给浏览器(顺带再把数据包发一份到stdout)。我没有研究过HTTP协议,因此我这里就不给出HTTP协议的详细的细节了。
  1. #include<stdio.h>
  2. #include<process.h>
  3. #include<winsock2.h>

  4. #define BUFSIZE 8192    //缓冲区大小

  5. #define TARGET_WEBSITE  "www.baidu.com"//要访问的网站

  6. SOCKET g_SockToServer=INVALID_SOCKET;
  7. SOCKET g_SockToBrowser=INVALID_SOCKET;

  8. void Repeater1(void *p)//转发器1:接收浏览器数据,转发到服务器
  9. {
  10.     char buffer[BUFSIZE+1]={0};
  11.     int moredata=0;
  12.     int nRecv=0;
  13.     for(;;)//从浏览器接收数据
  14.     {
  15.         memset(buffer,0,sizeof(buffer));
  16.         nRecv=recv(g_SockToBrowser,buffer,BUFSIZE,0);//接收数据
  17.         if(WSAGetLastError()==WSAEMSGSIZE)//如果WSAGetLastError为WSAEMSGSIZE,表示数据包大小超过了缓冲区
  18.         {
  19.             moredata=1;
  20.             nRecv=BUFSIZE;
  21.         }
  22.         else
  23.             moredata=0;
  24.         printf("浏览器数据包:\n%s\n",buffer);//输出到stdout
  25.         if(send(g_SockToServer,buffer,nRecv,0)!=nRecv)//转发
  26.         {
  27.             puts("转发失败。");
  28.             break;
  29.         }
  30.         if(!moredata)
  31.             break;
  32.     }
  33. }

  34. void Repeater2(void *p)//转发器2:接收服务器数据,转发到浏览器
  35. {
  36.     char buffer[BUFSIZE+1]={0};
  37.     int moredata=0;
  38.     int nRecv=0;
  39.     for(;;)//从服务器接收数据
  40.     {
  41.         memset(buffer,0,sizeof(buffer));
  42.         nRecv=recv(g_SockToServer,buffer,BUFSIZE,0);//接收数据
  43.         if(WSAGetLastError()==WSAEMSGSIZE)
  44.         {
  45.             moredata=1;
  46.             nRecv=BUFSIZE;
  47.         }
  48.         else
  49.             moredata=0;
  50.         printf("服务器数据包:\n%s\n",buffer);//输出到stdout
  51.         if(send(g_SockToBrowser,buffer,nRecv,0)!=nRecv)
  52.         {
  53.             puts("转发失败。");
  54.             break;
  55.         }
  56.         if(!moredata)
  57.             break;
  58.     }
  59. }

  60. void DealWithConn(SOCKET s,void*pBuffer,int nRecv)//处理单个连接的程序
  61. {
  62.     g_SockToBrowser=s;
  63.     g_SockToServer=socket(AF_INET,SOCK_STREAM,0);
  64.     do
  65.     {
  66.         SOCKADDR_IN sAddr={0};//连接目标
  67.         struct hostent *phostaddr;//域名解析
  68.         if(g_SockToServer==INVALID_SOCKET)
  69.         {
  70.             puts("socket失败\n");
  71.             break;
  72.         }
  73.         phostaddr=gethostbyname(TARGET_WEBSITE);//解析域名
  74.         if(!phostaddr)
  75.         {
  76.             puts("域名解析失败。");
  77.             break;
  78.         }
  79.         sAddr.sin_family=AF_INET;
  80.         sAddr.sin_port=htons(80);
  81.         sAddr.sin_addr.s_addr=*(u_long*)(phostaddr->h_addr_list[0]);
  82.         printf("服务器IP:%u.%u.%u.%u\n",
  83.             (unsigned char)phostaddr->h_addr_list[0][0],
  84.             (unsigned char)phostaddr->h_addr_list[0][1],
  85.             (unsigned char)phostaddr->h_addr_list[0][2],
  86.             (unsigned char)phostaddr->h_addr_list[0][3]);//打印IP
  87.         if(connect(g_SockToServer,(SOCKADDR*)&sAddr,sizeof(sAddr)))//连接到服务器
  88.         {
  89.             puts("连接不上目标。");
  90.             break;
  91.         }
  92.         _beginthread(Repeater1,0,NULL);//两个转发器同步执行
  93.         Repeater2(NULL);
  94.         puts("已断开连接。");
  95.         closesocket(g_SockToServer);//关闭连接
  96.         closesocket(g_SockToBrowser);
  97.         return;
  98.     }while(0);
  99.     printf("出BUG了。\nWSAGetLastError=%u\n",WSAGetLastError());
  100.     if(g_SockToServer!=INVALID_SOCKET)
  101.         closesocket(g_SockToServer);
  102.     closesocket(g_SockToBrowser);
  103. }

  104. int main()
  105. {
  106.     WSADATA wsaData;
  107.     SOCKET sockListener=INVALID_SOCKET;
  108.     SOCKET sockConn=INVALID_SOCKET;
  109.     if(WSAStartup(WINSOCK_VERSION,&wsaData))//初始化Winsock库
  110.     {
  111.         printf("WSAStartup失败。\n");
  112.         return 1;
  113.     }
  114.     do
  115.     {
  116.         SOCKADDR_IN sAddr={0};
  117.         char cDataRecv[BUFSIZE+1]={0};//多分配一个字节
  118.         int nRecv=0;
  119.         sockListener=socket(AF_INET,SOCK_STREAM,0);
  120.         if(sockListener==INVALID_SOCKET)
  121.         {
  122.             printf("socket失败\n");
  123.             break;
  124.         }
  125.         sAddr.sin_family=AF_INET;
  126.         sAddr.sin_port=htons(80);
  127.         sAddr.sin_addr.s_addr=INADDR_ANY;
  128.         if(bind(sockListener,(SOCKADDR*)&sAddr,sizeof(sAddr)))//绑定端口
  129.         {
  130.             printf("bind失败\n");
  131.             break;
  132.         }
  133.         if(listen(sockListener,SOMAXCONN))//监听
  134.         {
  135.             printf("listen失败\n");
  136.             break;
  137.         }
  138.         for(;;)
  139.         {
  140.             puts("等待建立连接。");
  141.             sockConn=accept(sockListener,NULL,NULL);//等待建立连接
  142.             if(sockConn!=INVALID_SOCKET)
  143.             {
  144.                 puts("已连接。");
  145.                 DealWithConn(sockConn,cDataRecv,nRecv);//处理单个连接
  146.             }
  147.         }
  148.         closesocket(sockListener);
  149.         return 0;
  150.     }while(0);
  151.     printf("遇到了某些问题。\nWSAGetLastError=%u\n",WSAGetLastError());
  152.     if(sockListener!=INVALID_SOCKET)
  153.         closesocket(sockListener);
  154.     if(sockConn!=INVALID_SOCKET)
  155.         closesocket(sockConn);
  156.     return 1;
  157. }
复制代码
详细的使用方法:
方法1、运行它,然后用浏览器直接上“http://localhost/”或“http://127.0.0.1/”虽然看不到数据,但是你能捕获浏览器给出的HTTP头。
方法2、运行它之前改hosts,把目标网站域名重定向到127.0.0.1,然后运行这个程序,用浏览器上目标网站,能捕获到完整的数据。
方法3、运行它,然后在局域网的另一台电脑(或虚拟机)用浏览器访问你的电脑IP。可以看到浏览器发送的数据包。

提示:
1、开启了IIS服务或Apache服务的请事先关闭这两个服务,以免因端口冲突导致这个程序无法运行。
2、我不能保证这个程序的可移植性(因为用到了WSAGetLastError来判断缓冲区外是否还有数据)。
3、本程序由0xAA55原创。转载请指明出处。
4、完整的VC6工程以及编译生成的EXE下载:(请先回帖。回帖后就能下载。)
游客,如果您要查看本帖隐藏内容请回复

补充一下,我这里给出两个截获的HTTP头的范例。一定要注意HTTP头后面的两个空行!
以下内容是IE10发送给服务器的数据包:
  1. GET /网页文件路径 HTTP/1.1
  2. Accept: text/html, application/xhtml+xml, */*
  3. Accept-Language: zh-CN
  4. User-Agent: Mozilla/5.0 (Windows NT 6.1; Trident/7.0; rv:11.0) like Gecko
  5. Accept-Encoding: gzip, deflate
  6. Host: 网站域名
  7. DNT: 1
  8. Connection: Keep-Alive
  9.  
  10.  
复制代码
以下内容是谷歌浏览器(Chrome)发送给服务器的数据包:
  1. GET /网页文件路径 HTTP/1.1
  2. Host: 网站域名
  3. Connection: keep-alive
  4. Cache-Control: max-age=0
  5. Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
  6. User-Agent: Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko)Chrome/33.0.1750.146 Safari/537.36
  7. Accept-Encoding: gzip,deflate,sdch
  8. Accept-Language: zh-CN,zh;q=0.8,en;q=0.6,ja;q=0.4
  9.  
  10.  
复制代码
回复

使用道具 举报

发表于 2014-3-11 19:56:43 | 显示全部楼层
系统自动沙发
回复 赞! 靠!

使用道具 举报

发表于 2014-3-11 21:41:51 | 显示全部楼层
原来监听器是这么写的
回复 赞! 靠!

使用道具 举报

发表于 2014-3-24 22:42:04 | 显示全部楼层
哈哈,正看这方面的代码的了~
回复 赞! 靠!

使用道具 举报

发表于 2014-3-26 16:26:00 | 显示全部楼层
学习了。good
回复 赞! 靠!

使用道具 举报

发表于 2017-11-22 17:18:03 | 显示全部楼层
666666666666666666
回复 赞! 靠!

使用道具 举报

卡卡 该用户已被删除
发表于 2017-11-23 14:15:57 | 显示全部楼层
提示: 作者被禁止或删除 内容自动屏蔽
回复

使用道具 举报

发表于 2017-12-20 23:54:00 | 显示全部楼层
转发程序现在挺多的
回复 赞! 靠!

使用道具 举报

本版积分规则

QQ|Archiver|小黑屋|技术宅的结界 ( 滇ICP备16008837号 )|网站地图

GMT+8, 2024-11-21 17:45 , Processed in 0.035913 second(s), 28 queries , Gzip On.

Powered by Discuz! X3.5

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表