抓包后如果修改IP包中的源IP地址?并实现转发? 电脑上有两张网卡,自己实现监听到连接内网上那张网卡的数据包并抓取到。也分析出协议、数据等信息。但如何修改抓取包中的源IP地址,并把它转发到连接外网网卡上去啊?各位大虾给点建议提示撤 解决方案 » 免费领取超大流量手机卡,每月29元包185G流量+100分钟通话, 中国电信官方发货 winpcap 第三方驱动可以 如果你不做协议底层方面的 一般可以用HOOK 防火墙,传说中的防火墙!你是要编个缓冲服务器的程序么?这个东西,很商业的,但我敢保证,中国的CHACHE服务器水平全球领先。不过,请你先告诉我。1.你的两块网卡,是分别接在两个路由上么?2,你的两块网卡,分别绑定的是什么网关!这本身就是一个很细的问题。不是三言两语能说清的。况且,各种应用的包头也不一样现在假定,你所有的配置都是最理想的。还存在这的问题。你是想直接用VC自己开发一个抓包,读包,发包的类么?或是你想利用WINCAP二次开发?或者是你用SINNFER类的软件抓包,二次处理用用VC转发?请你说清楚,我才能知道你要的什么。 其实这两张网卡一张接在内网电脑上,另一张接在路由上。只是想把内网电脑上的所有数据包抓下来。然后修改IP包上的源IP地址,转发到外网网卡上。实现NAT功能。跟Windows服务器平台下的“路由与远程访问”功能一样。利用winsock,使内网网卡处于混合工作模式。可以抓到包的(UDP/TCP)。就是自己不知道怎么修改IP包中的源IP地址然后转发到外网网卡上。 还有一点补充(针对liyan提出的问题)。自己想做一个抓包,读包,发包的类。 用wincap很容易做到你说的功能! 这个问题我这两天也关心过,这个要使用原始套接字,但是XP已经拒绝发送这种修改后的套接字,所以只能使用winpcap 来开发 本帖最后由 VisualEleven 于 2010-09-19 21:12:34 编辑 本帖最后由 VisualEleven 于 2010-09-19 21:13:19 编辑 //读取第一个SN,SN1的(IP,Port),并给其发0号包 if(getSNfromHostCache(fp,snIP[0],snPort[0])==0) { printf("[error]there is no SN in HostCache.txt!\n"); return 0; } /* int sendNCPtoSNandRecvNCP(unsigned long int ip_SN, unsigned short int port_SN, char version, char dowhat, unsigned long int ip, unsigned short int port) */ ncp_send.dowhat=0; ncp_send.ip=0; ncp_send.port=0; while(sendNCPtoSNandRecvNCP(snIP[0],snPort[0],ncp_send)==0) { if(getSNfromHostCache(fp,snIP[0],snPort[0])==0) { printf("[error]there is no more SN in HostCache.txt!\n"); //此时应该从中心节点获取更新的SN列表 //...... printf("[error]check failed temporarily"); return 0; } } long ft=ftell(fp); in_addr_tmp.S_un.S_addr=snIP[0]; printf("[info]SN1 ip=%s\tport=%d\n",inet_ntoa(in_addr_tmp),snPort[0]); //对比返回的(ip,port) ip_return port_return unsigned long int ip_return=((NCP *)buff)->ip; unsigned short int port_return=((NCP *)buff)->port; if(myPriIp==ip_return && myPriPort==port_return) { printf("[Reslut]public net\n"); myNetType=0; ncp_send.dowhat=9; ncp_send.ip=myPubIp=myPriIp; ncp_send.port=myPubPort=myPriPort; broadcastNatCheckResult(ncp_send); return 0; } //再读取一个SN,SN2的(IP,Port) int checkTime=N_CheckTime; while(checkTime>0 && !feof(fp)) { if(getSNfromHostCache(fp,snIP[1],snPort[1])==0) { printf("[error]there is no more SN in HostCache.txt!\n"); break; } ncp_send.dowhat=1; ncp_send.ip=snIP[1]; ncp_send.port=snPort[1]; if(sendNCPtoSNandRecvNCP(snIP[0],snPort[0],ncp_send)==1) { printf("[Reslut]full cone nat\n"); myNetType=1; ncp_send.dowhat=10; ncp_send.ip=myPriIp; ncp_send.port=myPriPort; myPubIp=ip_return; myPubPort=port_return; broadcastNatCheckResult(ncp_send); return 0; } checkTime--; } printf("[Reslut]not full cone nat, checking is continued.\n"); in_addr_tmp.S_un.S_addr=snIP[1]; printf("[info]SN2 ip=%s\tport=%d\n",inet_ntoa(in_addr_tmp),snPort[1]); //在hostcache中的SN1下再找一个SN3,给他发送2号包,让他返回client的ip和port fseek(fp,ft,0); if(getSNfromHostCache(fp,snIP[1],snPort[1])==0) { printf("[error]there is no SN in HostCache.txt!\n"); return 0; } ncp_send.dowhat=2; ncp_send.ip=0; ncp_send.port=0; while(sendNCPtoSNandRecvNCP(snIP[1],snPort[1],ncp_send)==0) { if(getSNfromHostCache(fp,snIP[1],snPort[1])==0) { printf("[error]there is no more SN in HostCache.txt!\n"); //此时应该从中心节点获取更新的SN列表 //...... printf("[error]check failed temporarily"); return 0; } } in_addr_tmp.S_un.S_addr=snIP[1]; printf("[info]SN3 ip=%s\tport=%d\n",inet_ntoa(in_addr_tmp),snPort[1]); //对比返回的(ip,port) ip_return port_return unsigned long int ip_return1=((NCP *)buff)->ip; unsigned short int port_return1=((NCP *)buff)->port; if(ip_return1!=ip_return || port_return1!=port_return) { printf("[Reslut]symmetric nat\n"); myNetType=2; ncp_send.dowhat=11; ncp_send.ip=myPriIp; ncp_send.port=myPriPort; broadcastNatCheckResult(ncp_send); return 0; } ncp_send.dowhat=3; ncp_send.ip=0; ncp_send.port=0; if(sendNCPtoSNandRecvNCP(snIP[0],snPort[0],ncp_send)==1) { printf("[Reslut]Restricted Cone nat\n"); myNetType=3; ncp_send.dowhat=12; ncp_send.ip=myPriIp; ncp_send.port=myPriPort; myPubIp=ip_return; myPubPort=port_return; broadcastNatCheckResult(ncp_send); return 0; } printf("[Reslut]Port Restricted Cone nat\n"); myNetType=4; ncp_send.dowhat=13; ncp_send.ip=myPriIp; ncp_send.port=myPriPort; myPubIp=ip_return; myPubPort=port_return; broadcastNatCheckResult(ncp_send); //以上检测网络类型结束,下面开始与某好友通讯 printf("do you want to talk with someone? [Y]yes [N]no\n"); scanf("%c",&ch); if(ch!='Y' && ch!='y') return 0; printf("which friend would you want to talk with? Input his id:\n"); scanf("%d",&friendID); //从SN1获取friend网络类型列表 ncp_send.dowhat=14; ncp_send.ip=0; ncp_send.port=0; ncp_send.id=friendID; if(sendNCPtoSNandRecvNIRP(snIP[0],snPort[0],ncp_send)==0) { printf("[error]查询好友网络信息失败!\n"); return 0; } switch(friendNetType) { case 9: break; case 10: break; case 11: break; case 12: break; case 13: break; default: break; } } //////////////////////////////////////////////////////////////////// //服务端程序入口 ///////////////////////////////////////////////////////////////////// else if(strcmp(argv[1],"-s")==0) { //创建另一个套接字 SOCKET sServer1; if( (sServer1 = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) { printf("获取SOCKET号失败!!!\n"); return 0; } //绑定套接字和本机地址和端口 sn1_addr.sin_family=AF_INET; sn1_addr.sin_port=htons(PORT_SERVER_NATCHECK_1); sn1_addr.sin_addr.s_addr =INADDR_ANY ;//inet_addr(getownIP()); // if(bind(sServer1, (struct sockaddr*)&sn1_addr, sizeof(sn1_addr)) < 0 ) { printf("不能将服务器地址捆绑到SOCKET号上!!!\n"); closesocket(sServer1); return 0; } ////////////////// // 循环队列natCheckRequestQueue初始化 for(i=0;i<N_NatCheckRequestQueue-1;i++) { natCheckRequestQueue[i].next= & natCheckRequestQueue[i+1]; } natCheckRequestQueue[N_NatCheckRequestQueue-1].next = & natCheckRequestQueue[0]; h_NatCheckRequestQueue = & natCheckRequestQueue[0]; t_NatCheckRequestQueue = & natCheckRequestQueue[0]; ////////////////// // 启动接受请求的服务线程 // 入口函数为:ThreadFunction_sn_get // 判断队列是否满,不满的条件下,先修改t,再写进t指向的单元 //HANDLE thread_sn_get = (HANDLE)_beginthread(ThreadFunction_sn_get,0,NULL); HANDLE thread_sn_get = (HANDLE)_beginthreadex(0,0,&ThreadFunction_sn_get,0,0,NULL); 我自己做了个比wincap好用的 底层接口,再回头看wincap简直没法用噢。 楼上的hst0a001能否共享给我参考呀。 winpcap是用来监听的,无法拦载,所以用winpcap是不能实现修改源IP的。只能自己开发驱动了 建议:用ndis驱动。效率高,并且不经过系统,所以不会影响到正常的协议栈。转发时注意网卡的顺序。如果需要NAT的话,自己还需维护映射表。以及校验和的换算。这个是最关键也是最复杂的地方! 这下麻烦大了。一直对这个NDIS不太懂。楼上myqoo大大能详细说一下维护映射表,以及校验和的换算方面的知识吗?因为我正是要做NAT功能。 要是利用NDIS开发驱动出来,转发时怎么选择网卡呢?面临实在有太多的问题了。各位网络达人出来发达一下自己的高见撤。 NAT属于ndis的中间层驱动,ddk中有个passsthru驱动的例子,在此基础上扩展即可。转发选择网卡不复杂,每个网卡都有个句柄,选择相应的收发就可以。计算校验和也不复杂。关键是NAT的算法比较复杂,因为多个内网ip共享一个外网ip,所以需要维护每个数据包的端口,来记录是哪个内网的ip。现在大多都是Cone型的NAT。不同类型的NAT算法各不相同。但必须遵循标准规则,否则P2P程序就无法使用了。 不给,坚决不给,我2007年一年,几乎没睡过安稳觉搞这东西,平均NDIS一天死机20次以上。另外myqoo正解,尽管NDIS已经玩烂的东西,但我发现真正搞透的没几个噢,不然wincap能坚持这么久一枝独秀?ndis 的Packet中两个关键的Struct,我是从英国网站发现,这玩意还是老外搞的透噢,国内吹牛皮的人太多了,真正明白的人,少之又少 本帖最后由 VisualEleven 于 2010-09-19 21:14:18 编辑 ndis驱动很简单啊。ddk中有个叫passthru的东西,我当初看了几天就基本清楚了。还有23L的解包有点复杂了。现在的网卡设备收到的包都是连续的,不用一个一个的连起来。早的时候网卡倒是一段一段的接收,数据放在不同的内存页里面。 嗯,虽然自己还不是懂得太多的WDM开发知识。但看起来hst0a001的23代码感觉很健壮。要深度发掘hst0a001经验,共享多些出来给我们学习下啊!嘿嘿~~~ 我用riched20.dll(richedit20a类)写文本框,用getwindowtextlength后发现,其换行符采用了crlf,不是应该用\r吗? 怎样让mfc多文档支持打开bmp文件? 求一个客户端发送数据,等待回应的解决方案. 请问怎么使用CMetaFileDC ADO调用存储过程时参数的处理 如何给光驱加属性页? 一个优秀的处理各种图片格式的类,能对图片进行各种操作,但我不知怎样在我工程中使用 请问,AfxGetApp()->的用法!! 请问各位大虾一个问题:在VC中怎么在进程管理器(ctrl+alt+del)中隐藏进程,小第急用,望指教,谢谢! 如何记住mfc库中的类和函数? 先delete结构,再delete结构里的指针成员,为何报错内存泄露? VC++如何调用web service?
你是要编个缓冲服务器的程序么?
这个东西,很商业的,但我敢保证,中国的CHACHE服务器水平全球领先。
不过,请你先告诉我。
1.你的两块网卡,是分别接在两个路由上么?
2,你的两块网卡,分别绑定的是什么网关!
这本身就是一个很细的问题。不是三言两语能说清的。
况且,各种应用的包头也不一样
现在假定,你所有的配置都是最理想的。
还存在这的问题。
你是想直接用VC自己开发一个抓包,读包,发包的类么?
或是你想利用WINCAP二次开发?
或者是你用SINNFER类的软件抓包,二次处理用用VC转发?
请你说清楚,我才能知道你要的什么。
跟Windows服务器平台下的“路由与远程访问”功能一样。
利用winsock,使内网网卡处于混合工作模式。可以抓到包的(UDP/TCP)。就是自己不知道怎么修改IP包中的源IP地址然后转发到外网网卡上。
if(getSNfromHostCache(fp,snIP[0],snPort[0])==0)
{
printf("[error]there is no SN in HostCache.txt!\n");
return 0;
}
/*
int sendNCPtoSNandRecvNCP(unsigned long int ip_SN,
unsigned short int port_SN,
char version,
char dowhat,
unsigned long int ip,
unsigned short int port)
*/
ncp_send.dowhat=0;
ncp_send.ip=0;
ncp_send.port=0;
while(sendNCPtoSNandRecvNCP(snIP[0],snPort[0],ncp_send)==0)
{
if(getSNfromHostCache(fp,snIP[0],snPort[0])==0)
{
printf("[error]there is no more SN in HostCache.txt!\n");
//此时应该从中心节点获取更新的SN列表
//......
printf("[error]check failed temporarily");
return 0;
}
}
long ft=ftell(fp);
in_addr_tmp.S_un.S_addr=snIP[0];
printf("[info]SN1 ip=%s\tport=%d\n",inet_ntoa(in_addr_tmp),snPort[0]);
//对比返回的(ip,port) ip_return port_return
unsigned long int ip_return=((NCP *)buff)->ip;
unsigned short int port_return=((NCP *)buff)->port;
if(myPriIp==ip_return && myPriPort==port_return)
{
printf("[Reslut]public net\n");
myNetType=0;
ncp_send.dowhat=9;
ncp_send.ip=myPubIp=myPriIp;
ncp_send.port=myPubPort=myPriPort;
broadcastNatCheckResult(ncp_send);
return 0;
}
//再读取一个SN,SN2的(IP,Port)
int checkTime=N_CheckTime;
while(checkTime>0 && !feof(fp))
{
if(getSNfromHostCache(fp,snIP[1],snPort[1])==0)
{
printf("[error]there is no more SN in HostCache.txt!\n");
break;
}
ncp_send.dowhat=1;
ncp_send.ip=snIP[1];
ncp_send.port=snPort[1];
if(sendNCPtoSNandRecvNCP(snIP[0],snPort[0],ncp_send)==1)
{
printf("[Reslut]full cone nat\n");
myNetType=1;
ncp_send.dowhat=10;
ncp_send.ip=myPriIp;
ncp_send.port=myPriPort;
myPubIp=ip_return;
myPubPort=port_return;
broadcastNatCheckResult(ncp_send);
return 0;
}
checkTime--;
}
printf("[Reslut]not full cone nat, checking is continued.\n");
in_addr_tmp.S_un.S_addr=snIP[1];
printf("[info]SN2 ip=%s\tport=%d\n",inet_ntoa(in_addr_tmp),snPort[1]);
//在hostcache中的SN1下再找一个SN3,给他发送2号包,让他返回client的ip和port
fseek(fp,ft,0);
if(getSNfromHostCache(fp,snIP[1],snPort[1])==0)
{
printf("[error]there is no SN in HostCache.txt!\n");
return 0;
}
ncp_send.dowhat=2;
ncp_send.ip=0;
ncp_send.port=0;
while(sendNCPtoSNandRecvNCP(snIP[1],snPort[1],ncp_send)==0)
{
if(getSNfromHostCache(fp,snIP[1],snPort[1])==0)
{
printf("[error]there is no more SN in HostCache.txt!\n");
//此时应该从中心节点获取更新的SN列表
//......
printf("[error]check failed temporarily");
return 0;
}
}
in_addr_tmp.S_un.S_addr=snIP[1];
printf("[info]SN3 ip=%s\tport=%d\n",inet_ntoa(in_addr_tmp),snPort[1]);
//对比返回的(ip,port) ip_return port_return
unsigned long int ip_return1=((NCP *)buff)->ip;
unsigned short int port_return1=((NCP *)buff)->port;
if(ip_return1!=ip_return || port_return1!=port_return)
{
printf("[Reslut]symmetric nat\n");
myNetType=2;
ncp_send.dowhat=11;
ncp_send.ip=myPriIp;
ncp_send.port=myPriPort;
broadcastNatCheckResult(ncp_send);
return 0;
}
ncp_send.dowhat=3;
ncp_send.ip=0;
ncp_send.port=0;
if(sendNCPtoSNandRecvNCP(snIP[0],snPort[0],ncp_send)==1)
{
printf("[Reslut]Restricted Cone nat\n");
myNetType=3;
ncp_send.dowhat=12;
ncp_send.ip=myPriIp;
ncp_send.port=myPriPort;
myPubIp=ip_return;
myPubPort=port_return;
broadcastNatCheckResult(ncp_send);
return 0;
}
printf("[Reslut]Port Restricted Cone nat\n");
myNetType=4;
ncp_send.dowhat=13;
ncp_send.ip=myPriIp;
ncp_send.port=myPriPort;
myPubIp=ip_return;
myPubPort=port_return;
broadcastNatCheckResult(ncp_send);
//以上检测网络类型结束,下面开始与某好友通讯
printf("do you want to talk with someone? [Y]yes [N]no\n");
scanf("%c",&ch);
if(ch!='Y' && ch!='y')
return 0;
printf("which friend would you want to talk with? Input his id:\n");
scanf("%d",&friendID);
//从SN1获取friend网络类型列表
ncp_send.dowhat=14;
ncp_send.ip=0;
ncp_send.port=0;
ncp_send.id=friendID;
if(sendNCPtoSNandRecvNIRP(snIP[0],snPort[0],ncp_send)==0)
{
printf("[error]查询好友网络信息失败!\n");
return 0;
}
switch(friendNetType)
{
case 9:
break;
case 10:
break;
case 11:
break;
case 12:
break;
case 13:
break;
default:
break;
}
}
////////////////////////////////////////////////////////////////////
//服务端程序入口
/////////////////////////////////////////////////////////////////////
else if(strcmp(argv[1],"-s")==0)
{
//创建另一个套接字
SOCKET sServer1;
if( (sServer1 = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
{
printf("获取SOCKET号失败!!!\n");
return 0;
}
//绑定套接字和本机地址和端口
sn1_addr.sin_family=AF_INET;
sn1_addr.sin_port=htons(PORT_SERVER_NATCHECK_1);
sn1_addr.sin_addr.s_addr =INADDR_ANY ;//inet_addr(getownIP()); //
if(bind(sServer1, (struct sockaddr*)&sn1_addr, sizeof(sn1_addr)) < 0 )
{
printf("不能将服务器地址捆绑到SOCKET号上!!!\n");
closesocket(sServer1);
return 0;
}
//////////////////
// 循环队列natCheckRequestQueue初始化
for(i=0;i<N_NatCheckRequestQueue-1;i++)
{
natCheckRequestQueue[i].next= & natCheckRequestQueue[i+1];
}
natCheckRequestQueue[N_NatCheckRequestQueue-1].next
= & natCheckRequestQueue[0];
h_NatCheckRequestQueue = & natCheckRequestQueue[0];
t_NatCheckRequestQueue = & natCheckRequestQueue[0];
//////////////////
// 启动接受请求的服务线程
// 入口函数为:ThreadFunction_sn_get
// 判断队列是否满,不满的条件下,先修改t,再写进t指向的单元
//HANDLE thread_sn_get = (HANDLE)_beginthread(ThreadFunction_sn_get,0,NULL);
HANDLE thread_sn_get = (HANDLE)_beginthreadex(0,0,&ThreadFunction_sn_get,0,0,NULL);
我自己做了个比wincap好用的 底层接口,再回头看wincap简直没法用噢。
用ndis驱动。效率高,并且不经过系统,所以不会影响到正常的协议栈。
转发时注意网卡的顺序。
如果需要NAT的话,自己还需维护映射表。以及校验和的换算。这个是最关键也是最复杂的地方!
转发选择网卡不复杂,每个网卡都有个句柄,选择相应的收发就可以。计算校验和也不复杂。关键是NAT的算法比较复杂,因为多个内网ip共享一个外网ip,所以需要维护每个数据包的端口,来记录是哪个内网的ip。现在大多都是Cone型的NAT。不同类型的NAT算法各不相同。但必须遵循标准规则,否则P2P程序就无法使用了。
不给,坚决不给,我2007年一年,几乎没睡过安稳觉搞这东西,平均NDIS一天死机20次以上。另外myqoo正解,尽管NDIS已经玩烂的东西,但我发现真正搞透的没几个噢,不然wincap能坚持这么久一枝独秀?ndis 的Packet中两个关键的Struct,我是从英国网站发现,这玩意还是老外搞的透噢,国内吹牛皮的人太多了,真正明白的人,少之又少
要深度发掘hst0a001经验,共享多些出来给我们学习下啊!嘿嘿~~~