位于网关后面的计算机直接进行通信(穿过防火墙),想知道别人是如何做到的!!!(200分)

  • 主题发起人 LiChaoHui
  • 开始时间
最近看了一些介绍网关文章,其实网关和代理服务器,以及防火墙都是相似的概念,
网关是一种透明代理,利用NAT技术实现透明代理,
网关可以支持外部网络连接到内部网络,要建立NAT表,
但是一般的宽带猫(接在HUB上的),都不允许这样做

对于每一条对外的访问链路,网关都在内存中保留了NAT映射,
(外部IP及端口和内部的IP及端口的映射转换表)
允许外部网络返回的数据能够准确到达,
利用缓存的NAT链路信息是达到此目的的关键

目前,还没有在网上找到此类问题的技术文章,如果有谁知道
千万告诉我一声
 
这个实现基本上是用UDP来完成的,同时也需要看网关的配置情况,如果网关配置支持动
态包过滤,而且可以在内部访问外部网络,这样就可以实现,仍然需要借助第三方,比
如动态DNS的解析和端口映射。
 
关注。

另外端口映射是如何做的。
 
监听然后转发
 
用ICMP包可以穿越绝大多数防火墙和网络设备。
 
使用ICMP协议能使都在网关后的计算机直接通信吗?
远程返回的ICMP应答数据包基本上可以穿过所有的防火墙
 
能贴上一些源代码吗?
 
随着Internet网络的普及,各个中大型公司均建立了自己的局域网络。而公司内部人员上网的限制也逐渐成为一个大家关心的话题。目前最为流行的网络工具大多是基于TCP/IP协议的,而其中最主要的两个协议就是TCP和UDP协议。HTTP,FTP等上层协议均是建立在TCP协议之上了,而DNS,ICQ,TFTP等则是建立在UDP协议之上的。往往我们会遇到这样情况:公司禁止了UDP协议,因为很大一部分的网络通讯软件都是建立在UDP协议之上的,而开通了TCP协议。这样,我们就可以通过TCP协议来为我们转发UDP数据报,具体实现原理可以参看eyas的《突破TCP-IP过滤/防火墙进入内网》,里面详细讨论了如何实现TCP与UDP数据报之间的相互转发,也可以参看本文相关软件T-QQ的源代码,里面也包含了TCP与UDP相互转发的功能,在此就不多说了。现在进入正题,如何实现用ICMP数据报来突破网关的限制?

ICMP协议(Internet Control Messages Protocol, 网际控制报文协议)是一种多功能的协议,在网络上有很多用处,比如ICMP扫描,拒绝服务(DOS)攻击,隧道攻击,以及我们最常用到的PING程序。而我们就是利用ICMP协议来为我们传送(TCP/UDP)数据。大家知道一般的防火墙都是过滤了来自外部主机的回送请求(echo Request)报文,但为了是自己能够探测外部主机的当前状态,防火墙都不会过滤掉回送应答(echo Reply)数据报,而且ICMP报文可以在广域网上传送,这样我们就可以利用它来突破网关的种种限制。本文主要针对使用ICMP协议来转发UDP数据报的功能,并以OICQ为背景,至于突破TCP的限制,也大同小异。
以下是QQicmp的工作原理:

----->----- ----->----- ----->-----
QQ客户端 < UDP > QQicmp(l) < ICMP > QQicmp(g) < UDP >Tencent服务器
-----<----- -----<----- -----<-----

其中QQ客户端和QQicmp(l)都运行在本机上,而QQicmp(g)则是运行在网关上(QQicmp(l) 与 QQicmp(g)均是同一程序,只是运行模式不同:-l 运行于本地主机, -g 运行于网关上),Tencent服务器我想大家都清楚吧。QQ客户端与QQicmp(l),QQicmp(g)与Tencent服务器之间以UDP通信,QQicmp(l)与QQicmp(g)之间则是以ICMP通信。 Win2000/xp都提供了自己构造数据报的功能,也就是我们可以自己定义发送数据报的各项内容,当然也可以监听通过主机的基于IP协议的各种数据报。为了发送ICMP数据报及接收所有的IP数据报,我们必须自定义数据报的格式及校验和的求解:
typedef struct ipheader
{
unsigned char h_lenver; //头部长度及版本
unsigned char tos; //服务类型
unsigned short total_len; //报文总长度
unsigned short ident; //信息包标志
unsigned short frag_and_flags; //标志及分段偏移量
unsigned char ttl; //生命周期
unsigned char proto; //协议类型
unsigned short checksum; //IP校验和
unsigned int sourceip; //源IP地址
unsigned int destip; //目的IP地址
}ipheader;

typedef struct icmpheader
{
unsigned char type; //ICMP类型 0->回送应答 8->回送请求
unsigned char code; //代码
unsigned short checksum; //校验和
unsigned short seq; //序号
unsigned short id; //标识符
}icmpheader;

unsigned short checksum(unsigned short *buffer,int size)
{
unsigned long cksum=0;
while(size>0) //各位求和
{
cksum+=*buffer++;
size-=sizeof(unsigned short);
}
if(size)
cksum+=*(unsigned char *)buffer;
cksum=(cksum>>16)+(cksum &amp; 0xffff);
cksum+=(cksum>>16);
return (unsigned short)(~cksum); //再求补
}

首先,我们更改QQ客户端里的服务器地址为127.0.0.1,端口改为QQicmp(l)的监听QQ客户端端口,当然你也可以保持默认的8000,这样QQicmp(l)就应该在8000端口监听QQ客户端的数据。同时,QQ客户端也在端口4000(假设为非内网主机上的第一个QQ)监听来自QQicmp(l)的数据报。
我们可以看到,QQicmp(l)的主要作用就是将接收到了来自QQ客户端的UPD数据报,
sock[0][0]=socket(AF_INET,SOCK_DGRAM,0); //创建基于UDP协议的套接字
bind(sock[0][0],(struct sockaddr *)&amp;sin[0][1],addrlen); //绑定到指定地址,指定端口上
iret=recvfrom(sock[0][0],msgrecv,sizeof(msgrecv),0,(struct sockaddr *)&amp;tempr,&amp;addrlen); //接收来自QQ客户端的UDP数据

然后以ICMP数据报的形式发送到QQicmp(g),在此需要自己构造ICMP echo Reply数据报,并将接收到的UDP数据报填充到ICMP报文的数据段,
sock[0][1]=socket(AF_INET,SOCK_RAW,IPPROTO_ICMP); //创建ICMP协议的原始套接字,用来发送自定义数据报
bind(sock[0][1],(struct sockaddr *)&amp;sin[0][2],addrlen); //并捆绑到指定地址,指定端口上

icmphdr.type=0; //类型:echo reply
icmphdr.code=0; //代码
icmphdr.id=htons(65456); //序号
icmphdr.seq=htons(65456); //标志符,用以过滤数据报
icmphdr.checksum=0;

if(istbcs==0) //填充ICMP数据报头部
{
memset(msgsend,0,sizeof(msgsend));
memcpy(msgsend,&amp;icmphdr,sizeof(icmphdr));
istbcs+=sizeof(icmphdr);
}
memcpy(msgsend+istbcs,msgrecv,iret); //将接收到的UDP数据报的内容提取,准备以ICMP的形式发送

iret=sendto(sock[0][1],msgsend,istbcs,0,(struct sockaddr *)&amp;sin[0][3],addrlen); //发送到网关
同时,QQicmp(l)监听通过本机的IP数据报,筛选出来自QQicmp(g)及网关的数据报,
sock[1][0]=socket(AF_INET,SOCK_RAW,IPPROTO_IP); //创建原始套接字,接收所有的IP数据报
bind(sock[1][0],(struct sockaddr *)&amp;sin[1][1],addrlen); //绑定到指定地址,端口

DWORD dwbufferlen[10];
DWORD dwbufferinlen=1;
DWORD dwbytesreturned=0;
WSAIoctl(sock[1][0],SIO_RCVALL,&amp;dwbufferinlen,sizeof(dwbufferinlen),&amp;dwbufferlen,sizeof(dwbufferlen),&amp;dwbytesreturned,NULL,NULL);
//设置为接收所有的数据报,需要mstcpip.h头文件,T-QQ相关文件里就有,或安装SDK

iret=recvfrom(sock[1][0],msgrecv,sizeof(msgrecv),0,(struct sockaddr *)&amp;temps,&amp;addrlen); //接收所有数据报
if(iret<=28) //文件过小
{
break;
}
if((icmphdr->type!=0) || (icmphdr->code!=0) || ((icmphdr->id)!=htons(65456)) || ((icmphdr->seq)!=htons(65456))) //不符合接收条件
{
break;
}

memcpy(msgsend+istbcs,msgrecv,iret); //将接收到的ICMP数据报的内容提取,准备以UDP的形式发送
解包后,用UDP数据报将接收到的来自网关的数据发送到QQ客户端,
idx=28; //ICMP数据报的前20字节是IP头部,接着的8字节是ICMP头部,
iret=sendto(sock[1][1],&amp;msgsend[idx],ileft,0,(struct sockaddr *)&amp;sin[1][3],addrlen); //发送到QQ客户端

我们创建了两个线程在两个方向(udp-->icmp,icmp-->udp)上接收并传送数据,如果某个线程出错,就重新创建该线程,而未出错的线程则保持不变,
hthreads[0]=CreateThread(NULL,0,u2i,(LPVOID)0,NULL,&amp;hthreadid[0]); //创建udp接收数据,icmp发送数据的线程0
hthreads[1]=CreateThread(NULL,0,i2u,(LPVOID)1,NULL,&amp;hthreadid[1]); //创建icmp接收数据,udp发送数据的线程1

while(1)
{
dwret=WaitForMultipleObjects(2,hthreads,false,INFINITE); //等待某个线程的结束
if(dwret==WAIT_FAILED) //等待出错
{
cout<<"WaitForMultipleObjects Error: "<<GetLastError()<<endl;
return -1;
}
log=dwret-WAIT_OBJECT_0;
if(log==0) //线程0结束
{
CloseHandle(hthreads[0]); //关闭线程handle
closesocket(sock[0][1]); //关闭套接字
hthreads[0]=CreateThread(NULL,0,u2i,(LPVOID)0,NULL,&amp;hthreadid[0]); //重新创建线程0
}
else if(log==1) //线程1结束
{
CloseHandle(hthreads[1]);
closesocket(sock[1][0]);
hthreads[1]=CreateThread(NULL,0,i2u,(LPVOID)1,NULL,&amp;hthreadid[1]);
}

以上就是QQicmp(l)的工作原理,QQicmp(g)运行在网关上,虽然模式不同,但工作原理是一样的,只是数据报的流动方向有点差异。
QQicmp之源代码如下:

#include <iostream.h>
#include <winsock2.h>
#include <windows.h>
#include <mstcpip.h>

#pragma comment (lib,"ws2_32")
#define maxsize 64*1024

typedef struct ipheader
{
unsigned char h_lenver;
unsigned char tos;
unsigned short total_len;
unsigned short ident;
unsigned short frag_and_flags;
unsigned char ttl;
unsigned char proto;
unsigned short checksum;
unsigned int sourceip;
unsigned int destip;
}ipheader;

typedef struct icmpheader
{
unsigned char type;
unsigned char code;
unsigned short checksum;
unsigned short seq;
unsigned short id;
}icmpheader;

unsigned short checksum(unsigned short *buffer,int size)
{
unsigned long cksum=0;
while(size>0)
{
cksum+=*buffer++;
size-=sizeof(unsigned short);
}
if(size)
cksum+=*(unsigned char *)buffer;
cksum=(cksum>>16)+(cksum &amp; 0xffff);
cksum+=(cksum>>16);
return (unsigned short)(~cksum);
}

void start()
{
cout<<" ---------------------------------------------------/n";
cout<<" || || /n";
cout<<" || QQicmp (ICMP转发) || /n";
cout<<" || || /n";
cout<<" || Author:TOo2y SafeChina || /n";
cout<<" || || /n";
cout<<" ---------------------------------------------------"<<endl;
}

void usage()
{
cout<<"/nUsage:/r/n/tQQicmp -l[-g] ip port"<<endl;
cout<<"/tQQicmp -h"<<endl;
cout<<"Example:/r/n";
cout<<"/tQQicmp -l 192.168.0.1 8000"<<endl;
cout<<"/tQQicmp -g 61.144.238.156 11282"<<endl;
cout<<"Attention:"<<endl;
cout<<"/t选项 -l : 运行于本机上,ip填网关地址,port为本地监听客户端端口;"<<endl;
cout<<"/t选项 -g : 运行于网关上,ip填腾讯服务器地址,port为自定义端口;"<<endl;
cout<<"/t选项 -h : 查看相关帮助文件。"<<endl;
}

int addrlen=sizeof(struct sockaddr_in);
SOCKET sock[2][2];
struct sockaddr_in sin[2][4],sag,sal,tempr,temps;

DWORD WINAPI u2i(LPVOID num)
{
UNREFERENCED_PARAMETER(num);
char msgrecv[maxsize]={0},msgsend[maxsize]={0};
fd_set fdread,fdwrite;
int iret,ret,istbcs=0;
struct icmpheader icmphdr;

memset(&amp;icmphdr,0,sizeof(icmphdr));
icmphdr.code=0;
icmphdr.id=htons(65456);
icmphdr.seq=htons(65456);
icmphdr.type=0;
icmphdr.checksum=checksum((unsigned short *)&amp;icmphdr,sizeof(icmphdr));

if((sock[0][1]=socket(AF_INET,SOCK_RAW,IPPROTO_ICMP))==INVALID_SOCKET)
{
cout<<"Socket sock[0][1] Error: "<<GetLastError()<<endl;
return -1;
}
if(bind(sock[0][1],(struct sockaddr *)&amp;sin[0][2],addrlen)==SOCKET_ERROR)
{
cout<<"Bind sock[0][1] Error: "<<GetLastError()<<endl;
return -1;
}

while(1)
{
FD_ZERO(&amp;fdread);
FD_ZERO(&amp;fdwrite);
FD_SET(sock[0][0],&amp;fdread);
FD_SET(sock[0][1],&amp;fdwrite);

if((ret=select(0,&amp;fdread,&amp;fdwrite,NULL,NULL))==SOCKET_ERROR)
{
cout<<"Select in thread 0 Error: "<<GetLastError()<<endl;
break;
}
if(ret>0)
{
if(FD_ISSET(sock[0][0],&amp;fdread))
{
iret=recvfrom(sock[0][0],msgrecv,sizeof(msgrecv),0,(struct sockaddr *)&amp;tempr,&amp;addrlen);
if(iret==SOCKET_ERROR)
{
cout<<"/nRecvfrom sock[0][0] Error: "<<GetLastError()<<endl;
break;
}
else if(iret==0)
{
cout<<"Iret==0"<<endl;
break;
}
cout<<"/nThread 0 Recv "<<iret<<" bytes from/t"<<inet_ntoa(tempr.sin_addr)<<endl;
if(istbcs==0)
{
memset(msgsend,0,sizeof(msgsend));
memcpy(msgsend,&amp;icmphdr,sizeof(icmphdr));
istbcs+=sizeof(icmphdr);
}
memcpy(msgsend+istbcs,msgrecv,iret);
istbcs+=iret;
memset(msgrecv,0,sizeof(msgrecv));
}
else if(FD_ISSET(sock[0][1],&amp;fdwrite))
{

while(istbcs>0)
{

if(sin[0][3].sin_addr.s_addr==htonl(0))
{
cout<<"sin[0][3].sin_addr.s_addr==htonl(0)"<<endl;
istbcs=0;
memset(msgsend,0,sizeof(msgsend));
break;
}

iret=sendto(sock[0][1],msgsend,istbcs,0,(struct sockaddr *)&amp;sin[0][3],addrlen);
if(iret==SOCKET_ERROR)
{
cout<<"Sendto sock[0][1] Error: "<<GetLastError()<<endl;
break;
}
cout<<"Thread 0 send "<<iret<<" bytes to /t"<<inet_ntoa(sin[0][3].sin_addr)<<endl;
istbcs-=iret;
}
memset(msgsend,0,sizeof(msgsend));
istbcs=0;
}
Sleep(20);
}
}
return 0;
}


DWORD WINAPI i2u(LPVOID num)
{
UNREFERENCED_PARAMETER(num);
fd_set fdread,fdwrite;
char msgrecv[maxsize]={0},msgsend[maxsize]={0};
int ret,iret,idx,istbcs=0,ileft;
DWORD dwbufferlen[10];
DWORD dwbufferinlen=1;
DWORD dwbytesreturned=0;
struct ipheader *iphdr;
struct icmpheader *icmphdr;

if((sock[1][0]=socket(AF_INET,SOCK_RAW,IPPROTO_IP))==INVALID_SOCKET)
{
cout<<"Socket sock[1][0] Error: "<<GetLastError()<<endl;
return -1;
}
if(bind(sock[1][0],(struct sockaddr *)&amp;sin[1][1],addrlen)==SOCKET_ERROR)
{
cout<<"Bind sock[1][0] Error: "<<GetLastError()<<endl;
return -1;
}

WSAIoctl(sock[1][0],SIO_RCVALL,&amp;dwbufferinlen,sizeof(dwbufferinlen),&amp;dwbufferlen,sizeof(dwbufferlen),&amp;dwbytesreturned,NULL,NULL);
iphdr=(struct ipheader *)msgrecv;
icmphdr=(struct icmpheader *)(msgrecv+sizeof(struct ipheader));

while(1)
{
FD_ZERO(&amp;fdread);
FD_ZERO(&amp;fdwrite);
FD_SET(sock[1][0],&amp;fdread);
FD_SET(sock[1][1],&amp;fdwrite);

if((ret=select(0,&amp;fdread,&amp;fdwrite,NULL,NULL))==SOCKET_ERROR)
{
cout<<"Select in thread 1 Error: "<<GetLastError()<<endl;
break;
}
if(ret>0)
{
if(FD_ISSET(sock[1][0],&amp;fdread))
{
{
iret=recvfrom(sock[1][0],msgrecv,sizeof(msgrecv),0,(struct sockaddr *)&amp;temps,&amp;addrlen);
if(iret==SOCKET_ERROR)
{
cout<<"Recvfrom sock[1][0] Error: "<<GetLastError()<<endl;
break;
}

if(iret<=28)
{
break;
}
if((icmphdr->type!=0) || (icmphdr->code!=0) || ((icmphdr->id)!=htons(65456)) || ((icmphdr->seq)!=htons(65456)))
{
break;
}
if((sin[1][0].sin_addr.s_addr!=htonl(0)) &amp;&amp; (sin[1][0].sin_addr.s_addr!=temps.sin_addr.s_addr))
break;
}
else if(sin[1][0].sin_addr.s_addr==htonl(0))
{
sin[1][0].sin_addr.s_addr=temps.sin_addr.s_addr;
sin[0][3].sin_addr.s_addr=temps.sin_addr.s_addr;
cout<<"sin[0][3] ==> "<<inet_ntoa(sin[0][3].sin_addr)<<endl;
}

cout<<"/nThread 1 Recv "<<iret<<" bytes from /t"<<inet_ntoa(temps.sin_addr)<<endl;

memcpy(msgsend+istbcs,msgrecv,iret);
istbcs+=iret;
memset(msgrecv,0,sizeof(msgrecv));
}
}
else if(FD_ISSET(sock[1][1],&amp;fdwrite))
{
ileft=istbcs-28;
idx=28;
while(ileft>0)
{
iret=sendto(sock[1][1],&amp;msgsend[idx],ileft,0,(struct sockaddr *)&amp;sin[1][3],addrlen);
if(iret==SOCKET_ERROR)
{
cout<<"Sendto sock[1][1] Error: "<<GetLastError()<<endl;
break;
}
cout<<"Thread 1 send "<<iret<<" bytes to /t"<<inet_ntoa(sin[1][3].sin_addr)<<endl;
ileft-=iret;
idx+=iret;
}
istbcs=0;
memset(msgsend,0,sizeof(msgsend));
}
Sleep(20);
}
}
return 0;
}


int main(int argc,char *argv[])
{
WSADATA wsa;
BOOL gl;
HANDLE hthreads[2];
DWORD hthreadid[2];
struct hostent *hp;
char cname[100];
int dwret,log;

system("cls.exe");
start();

if(argc==2)
{
if(strcmp(argv[1],"-h")==0)
{
ShellExecute(NULL,"open","help.txt",NULL,NULL,SW_SHOWMAXIMIZED);
return 0;
}
else
{
usage();
return -1;
}
}
else if(argc!=4)
{
usage();
return -1;
}
if(!strcmp(argv[1],"-g"))
gl=true;
else if(!strcmp(argv[1],"-l"))
gl=false;
else
{
usage();
return -1;
}

if(WSAStartup(MAKEWORD(2,2),&amp;wsa)!=0)
{
cout<<"WSAStartup Error: "<<GetLastError()<<endl;
return -1;
}

gethostname(cname,sizeof(cname));
hp=gethostbyname(cname);
for(int ipnum=0;hp->h_addr_list[ipnum]!=NULL;ipnum++)
sag.sin_addr=*(in_addr *)hp->h_addr_list[ipnum];
sag.sin_family=AF_INET;
sag.sin_port=htons(65456);

sal=sag;
if(ipnum>1)
sal.sin_addr=*(in_addr *)hp->h_addr_list[ipnum-2];

if(gl)
{
sin[0][0].sin_addr.s_addr=inet_addr(argv[2]);
sin[0][0].sin_family=AF_INET;
sin[0][0].sin_port=htons(8000);

sin[0][1].sin_addr.s_addr=htonl(INADDR_ANY);
sin[0][1].sin_family=AF_INET;
sin[0][1].sin_port=htons(atoi(argv[3]));

sin[0][2]=sal;

memset(&amp;sin[0][3],0,sizeof(sin[0][3]));
sin[0][3].sin_family=AF_INET;
}
else
{
sin[0][0].sin_addr.s_addr=inet_addr("127.0.0.1");
sin[0][0].sin_family=AF_INET;
sin[0][0].sin_port=htons(4000);

sin[0][1].sin_addr.s_addr=htonl(INADDR_ANY);
sin[0][1].sin_family=AF_INET;
sin[0][1].sin_port=htons(atoi(argv[3]));

sin[0][2]=sal;

sin[0][3].sin_addr.s_addr=inet_addr(argv[2]);
sin[0][3].sin_family=AF_INET;
}
sin[1][0]=sin[0][3];
sin[1][1]=sin[0][2];
sin[1][2]=sin[0][1];
sin[1][3]=sin[0][0];

if((sock[0][0]=socket(AF_INET,SOCK_DGRAM,0))==INVALID_SOCKET)
{
cout<<"Socket sock[0][0] Error: "<<GetLastError()<<endl;
return -1;
}
if(bind(sock[0][0],(struct sockaddr *)&amp;sin[0][1],addrlen)==SOCKET_ERROR)
{
cout<<"Bind sock[0][0] Error: "<<GetLastError()<<endl;
return -1;
}
sock[1][1]=sock[0][0];

cout<<"/n正常工作中..."<<endl;

hthreads[0]=CreateThread(NULL,0,u2i,(LPVOID)0,NULL,&amp;hthreadid[0]);
hthreads[1]=CreateThread(NULL,0,i2u,(LPVOID)1,NULL,&amp;hthreadid[1]);
while(1)
{
dwret=WaitForMultipleObjects(2,hthreads,false,INFINITE);
if(dwret==WAIT_FAILED)
{
cout<<"WaitForMultipleObjects Error: "<<GetLastError()<<endl;
return -1;
}
log=dwret-WAIT_OBJECT_0;
if(log==0)
{
CloseHandle(hthreads[0]);
closesocket(sock[0][1]);
hthreads[0]=CreateThread(NULL,0,u2i,(LPVOID)0,NULL,&amp;hthreadid[0]);
}
else if(log==1)
{
CloseHandle(hthreads[1]);
closesocket(sock[1][0]);
hthreads[1]=CreateThread(NULL,0,i2u,(LPVOID)1,NULL,&amp;hthreadid[1]);
}
else
{
for(int no1=0;no1<2;no1++)
{
CloseHandle(hthreads[no1]);
for(int no2=0;no2<2;no2++)
closesocket(sock[no1][no2]);
}
}
}
WSACleanup();
return 0;
}

本文相关软件T-QQ主要针对禁止使用QQ的网关,提供UDP,TCP及ICMP数据报转发功能,本软件同样适用于各种基于UDP协议的通信软件。其中的TCP数据报转发功能,也可以使用UDP数据报来转发TCP数据。相关软件及源代码下载地址: http://www.cshu.net/down/t-qq.rar
 
QQ代码?
 
感兴趣,但没时间。供参考:

{
----------------------------------------------------------------------
Raw Packet Sender
using: Delphi + Winsock 2

Copyright (c) 2000 by E.J.Molendijk (xes@dds.nl)


Description:

Using raw sockets you can SEND raw packets over the internet
containing whatever you like.

Keep in mind:

1. This only works under Window 2000.

2. You can SEND raw packets. You can NOT RECEIVE raw packets.

3. You must be Administrator to run this.

4. This unit requires a form containing a button and a memo.


Usage:
1. Before you run your program, you must change the SrcIP+SrcPort+
DestIP+DestPort to suitable values!

2. If you don't understand what this source does: Don't use it.

----------------------------------------------------------------------
}
unit main;

interface

uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls, OleCtrls, Registry;

Const
SrcIP = '123.123.123.1';
SrcPort = 1234;
DestIP = '123.123.123.2';
DestPort = 4321;

Max_Message = 4068;
Max_Packet = 4096;

type

TPacketBuffer = Array[0..Max_Packet-1] of byte;

TForm1 = class(TForm)
Button1: TButton;
Memo1: TMemo;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
procedure SendIt;
end;

// IP Header
type
T_IP_Header = record
ip_verlen : Byte;
ip_tos : Byte;
ip_totallength : Word;
ip_id : Word;
ip_offset : Word;
ip_ttl : Byte;
ip_protocol : Byte;
ip_checksum : Word;
ip_srcaddr : LongWord;
ip_destaddr : LongWord;
end;

// UDP Header
Type
T_UDP_Header = record
src_portno : Word;
dst_portno : Word;
udp_length : Word;
udp_checksum : Word;
end;

// Some Winsock 2 type declarations
u_char = Char;
u_short = Word;
u_int = Integer;
u_long = Longint;

SunB = packed record
s_b1, s_b2, s_b3, s_b4: u_char;
end;
SunW = packed record
s_w1, s_w2: u_short;
end;
in_addr = record
case integer of
0: (S_un_b: SunB);
1: (S_un_w: SunW);
2: (S_addr: u_long);
end;
TInAddr = in_addr;
Sockaddr_in = record
case Integer of
0: (sin_family: u_short;
sin_port: u_short;
sin_addr: TInAddr;
sin_zero: array[0..7] of Char);
1: (sa_family: u_short;
sa_data: array[0..13] of Char)
end;
TSockAddr = Sockaddr_in;
TSocket = u_int;

const
WSADESCRIPTION_LEN = 256;
WSASYS_STATUS_LEN = 128;

type
PWSAData = ^TWSAData;
WSAData = record // !!! also WSDATA
wVersion: Word;
wHighVersion: Word;
szDescription: array[0..WSADESCRIPTION_LEN] of Char;
szSystemStatus: array[0..WSASYS_STATUS_LEN] of Char;
iMaxSockets: Word;
iMaxUdpDg: Word;
lpVendorInfo: PChar;
end;
TWSAData = WSAData;

// Define some winsock 2 functions
function closesocket(s: TSocket): Integer; stdcall;
function socket(af, Struct, protocol: Integer): TSocket; stdcall;
function sendto(s: TSocket; var Buf; len, flags: Integer; var addrto: TSockAddr;
tolen: Integer): Integer; stdcall;{}
function setsockopt(s: TSocket; level, optname: Integer; optval: PChar;
optlen: Integer): Integer; stdcall;
function inet_addr(cp: PChar): u_long; stdcall; {PInAddr;} { TInAddr }
function htons(hostshort: u_short): u_short; stdcall;
function WSAGetLastError: Integer; stdcall;
function WSAStartup(wVersionRequired: word; var WSData: TWSAData): Integer; stdcall;
function WSACleanup: Integer; stdcall;

const
AF_INET = 2; // internetwork: UDP, TCP, etc.

IP_HDRINCL = 2; // IP Header Include

SOCK_RAW = 3; // raw-protocol interface

IPPROTO_IP = 0; // dummy for IP
IPPROTO_TCP = 6; // tcp
IPPROTO_UDP = 17; // user datagram protocol
IPPROTO_RAW = 255; // raw IP packet

INVALID_SOCKET = TSocket(NOT(0));
SOCKET_ERROR = -1;

var
Form1: TForm1;

implementation

// Import Winsock 2 functions
const WinSocket = 'WS2_32.DLL';

function closesocket; external winsocket name 'closesocket';
function socket; external winsocket name 'socket';
function sendto; external winsocket name 'sendto';
function setsockopt; external winsocket name 'setsockopt';
function inet_addr; external winsocket name 'inet_addr';
function htons; external winsocket name 'htons';
function WSAGetLastError; external winsocket name 'WSAGetLastError';
function WSAStartup; external winsocket name 'WSAStartup';
function WSACleanup; external winsocket name 'WSACleanup';


{$R *.DFM}

//
// Function: checksum
//
// Description:
// This function calculates the 16-bit one's complement sum
// for the supplied buffer
//
function CheckSum(Var Buffer; Size : integer) : Word;
type
TWordArray = Array[0..1] of Word;
var
ChkSum : LongWord;
i : Integer;
begin
ChkSum := 0;
i := 0;
While Size > 1 do begin
ChkSum := ChkSum + TWordArray(Buffer);
inc(i);
Size := Size - SizeOf(Word);
end;

if Size=1 then ChkSum := ChkSum + Byte(TWordArray(Buffer));

ChkSum := (ChkSum shr 16) + (ChkSum and $FFFF);
ChkSum := ChkSum + (Chksum shr 16);

Result := Word(ChkSum);
end;


procedure BuildHeaders(
FromIP : String;
iFromPort : Word;
ToIP : String;
iToPort : Word;
StrMessage : String;
Var Buf : TPacketBuffer;
Var remote : TSockAddr;
Var iTotalSize : Word
);
Var
dwFromIP : LongWord;
dwToIP : LongWord;

iIPVersion : Word;
iIPSize : Word;
ipHdr : T_IP_Header;
udpHdr : T_UDP_Header;

iUdpSize : Word;
iUdpChecksumSize : Word;
cksum : Word;

Ptr : ^Byte;

procedure IncPtr(Value : Integer);
begin
ptr := pointer(integer(ptr) + Value);
end;

begin
// Convert ip address'ss

dwFromIP := inet_Addr(PChar(FromIP));
dwToIP := inet_Addr(PChar(ToIP));

// Initalize the IP header
//
iTotalSize := sizeof(ipHdr) + sizeof(udpHdr) + length(strMessage);

iIPVersion := 4;
iIPSize := sizeof(ipHdr) div sizeof(LongWord);
//
// IP version goes in the high order 4 bits of ip_verlen. The
// IP header length (in 32-bit words) goes in the lower 4 bits.
//
ipHdr.ip_verlen := (iIPVersion shl 4) or iIPSize;
ipHdr.ip_tos := 0; // IP type of service
ipHdr.ip_totallength := htons(iTotalSize); // Total packet len
ipHdr.ip_id := 0; // Unique identifier: set to 0
ipHdr.ip_offset := 0; // Fragment offset field
ipHdr.ip_ttl := 128; // Time to live
ipHdr.ip_protocol := $11; // Protocol(UDP)
ipHdr.ip_checksum := 0 ; // IP checksum
ipHdr.ip_srcaddr := dwFromIP; // Source address
ipHdr.ip_destaddr := dwToIP; // Destination address
//
// Initalize the UDP header
//
iUdpSize := sizeof(udpHdr) + length(strMessage);

udpHdr.src_portno := htons(iFromPort) ;
udpHdr.dst_portno := htons(iToPort) ;
udpHdr.udp_length := htons(iUdpSize) ;
udpHdr.udp_checksum := 0 ;
//
// Build the UDP pseudo-header for calculating the UDP checksum.
// The pseudo-header consists of the 32-bit source IP address,
// the 32-bit destination IP address, a zero byte, the 8-bit
// IP protocol field, the 16-bit UDP length, and the UDP
// header itself along with its data (padded with a 0 if
// the data is odd length).
//
iUdpChecksumSize := 0;

ptr := @buf[0];
FillChar(Buf, SizeOf(Buf), 0);

Move(ipHdr.ip_srcaddr, ptr^, SizeOf(ipHdr.ip_srcaddr));
IncPtr(SizeOf(ipHdr.ip_srcaddr));

iUdpChecksumSize := iUdpChecksumSize + sizeof(ipHdr.ip_srcaddr);

Move(ipHdr.ip_destaddr, ptr^, SizeOf(ipHdr.ip_destaddr));
IncPtr(SizeOf(ipHdr.ip_destaddr));

iUdpChecksumSize := iUdpChecksumSize + sizeof(ipHdr.ip_destaddr);

IncPtr(1);

Inc(iUdpChecksumSize);

Move(ipHdr.ip_protocol, ptr^, sizeof(ipHdr.ip_protocol));
IncPtr(sizeof(ipHdr.ip_protocol));
iUdpChecksumSize := iUdpChecksumSize + sizeof(ipHdr.ip_protocol);

Move(udpHdr.udp_length, ptr^, sizeof(udpHdr.udp_length));
IncPtr(sizeof(udpHdr.udp_length));
iUdpChecksumSize := iUdpChecksumSize + sizeof(udpHdr.udp_length);

move(udpHdr, ptr^, sizeof(udpHdr));
IncPtr(sizeof(udpHdr));
iUdpChecksumSize := iUdpCheckSumSize + sizeof(udpHdr);

Move(StrMessage[1], ptr^, Length(strMessage));
IncPtr(Length(StrMessage));

iUdpChecksumSize := iUdpChecksumSize + length(strMessage);

cksum := checksum(buf, iUdpChecksumSize);
udpHdr.udp_checksum := cksum;

//
// Now assemble the IP and UDP headers along with the data
// so we can send it
//
FillChar(Buf, SizeOf(Buf), 0);
Ptr := @Buf[0];

Move(ipHdr, ptr^, SizeOf(ipHdr)); IncPtr(SizeOf(ipHdr));
Move(udpHdr, ptr^, SizeOf(udpHdr)); IncPtr(SizeOf(udpHdr));
Move(StrMessage[1], ptr^, length(StrMessage));

// Apparently, this SOCKADDR_IN structure makes no difference.
// Whatever we put as the destination IP addr in the IP header
// is what goes. Specifying a different destination in remote
// will be ignored.
//
remote.sin_family := AF_INET;
remote.sin_port := htons(iToPort);
remote.sin_addr.s_addr := dwToIP;
end;

procedure TForm1.SendIt;
Var
sh : TSocket;
bOpt : Integer;
ret : Integer;
Buf : TPacketBuffer;
Remote : TSockAddr;
Local : TSockAddr;
iTotalSize : Word;
wsdata : TWSAdata;

begin
// Startup Winsock 2
ret := WSAStartup($0002, wsdata);
if ret<>0 then begin
memo1.lines.add('WSA Startup failed.');
exit;
end;
with memo1.lines do begin
add('WSA Startup:');
add('Desc.: '+wsData.szDescription);
add('Status: '+wsData.szSystemStatus);
end;

try
// Create socket
sh := Socket(AF_INET, SOCK_RAW, IPPROTO_UDP);
if (sh = INVALID_SOCKET) then begin
memo1.lines.add('Socket() failed: '+IntToStr(WSAGetLastError));
exit;
end;
Memo1.lines.add('Socket Handle = '+IntToStr(sh));

// Option: Header Include
bOpt := 1;
ret := SetSockOpt(sh, IPPROTO_IP, IP_HDRINCL, @bOpt, SizeOf(bOpt));
if ret = SOCKET_ERROR then begin
Memo1.lines.add('setsockopt(IP_HDRINCL) failed: '+IntToStr(WSAGetLastError));
exit;
end;

// Build the packet
BuildHeaders( SrcIP, SrcPort,
DestIP, DestPort,
'THIS IS A TEST PACKET',
Buf, Remote, iTotalSize );

// Send the packet
ret := SendTo(sh, buf, iTotalSize, 0, Remote, SizeOf(Remote));
if ret = SOCKET_ERROR then
Memo1.Lines.Add('sendto() failed: '+IntToStr(WSAGetLastError))
else
Memo1.Lines.Add('send '+IntToStr(ret)+' bytes.');

// Close socket
CloseSocket(sh);
finally
// Close Winsock 2
WSACleanup;
end;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
SendIt;
end;

end.

 
多人接受答案了。
 
顶部