求高手帮忙,谢谢
这个抓包解包的程序能运行,可是有一个问题就是源IP地址和目的IP地址老是一样的。我想了很久也不知道原因,求教高手
#include <winsock2.h>
#include <ws2tcpip.h>
#define SIO_RCVALL _WSAIOW(IOC_VENDOR,1)
#include <iostream.h>
#include "stdio.h"
#include <string>
//#include "iostream.h"
#include <list>
#include <vector>
using namespace std;
# define null 0
# define len sizeof(struct node)
#pragma comment(lib,"ws2_32")
//#define TCP 6
//#define UDP 17
//#define ICMP 1
#define PROTO_TCP 6
#define PROTO_UDP 17
#define PROTO_ICMP 1
typedef struct ip_header
{// IPv4 包头
unsigned char ver_ihl; // 版本 (4 bits) + 包头长度(4 bits)
unsigned char tos; // 服务类型
unsigned short total_len; // 数据包的总长度
unsigned short id; // ID号
unsigned short flag_offset; // 标志 (3 bits) + 分片偏移 (13 bits)
unsigned char ttl; // 生存时间
unsigned char proto; // 协议
unsigned short checksum; //校验
unsigned int saddr; // 源地址
unsigned int daddr; // 目的地址
unsigned int opt; //IP选项和填充
}IP_HEADER;
typedef struct tcp_header
{
unsigned short sport;
unsigned short dport;
unsigned long seq; //32位的序列号
unsigned long ack; //32位的确认号
unsigned char head_len; //4位长度和4位保留
unsigned char flag; //标志位(高6位为码元标志位,低2位保留)
unsigned short win; //窗口
unsigned short checksum; //校验和
unsigned short urg; //紧急指针
}TCP_HEADER;
typedef struct udp_header
{//UDP 头
unsigned short sport; // 源端口
unsigned short dport; // 目击端口
unsigned short length; // 包长度
unsigned short checksum; // 校验
}UDP_HEADER;
typedef struct icmp_header
{
char type; //类型字节(1字节)
char code; //代码字节(1字节)
unsigned short checksum; //校验码(2字节)
}ICMP_HEADER;
class RawSocket
{
public:
RawSocket();
virtual ~RawSocket();
public:
SOCKET s;
char*GetIP();
void NetInit();
char*GetRawPacket();
};
RawSocket::RawSocket()
{
}
RawSocket::~RawSocket()
{
}
char*RawSocket::GetIP() //这个的IP应该是主机的IP?
{
char*hostname=new char[256];
memset(hostname,0,256);
gethostname(hostname,256);
struct hostent *phost=gethostbyname(hostname);
//printf("phost:%d\n",phost);
if(phost==NULL)
{
cout<<"pHost 为空"<<"gethostbyname()错误"<<endl;
return NULL;
}
in_addr*pAddr=(in_addr*)&phost->h_addr_list[0];
//printf("pAddr:%d\n",pAddr);
return inet_ntoa(*pAddr);
}
void RawSocket::NetInit()
{
WSADATA wsa;
if(WSAStartup(MAKEWORD(2,2),&wsa)!=0)
{
cout<<"WSAStartup Error:"<<GetLastError()<<endl;
return;
}
s=socket(AF_INET,SOCK_RAW,IPPROTO_IP);
if(s==INVALID_SOCKET)
{
cout<<"Create socket error:"<<GetLastError()<<endl;
return;
}
sockaddr_in addr;
addr.sin_family=AF_INET;
addr.sin_addr.s_addr=inet_addr("61.149.185.201");
addr.sin_port=ntohs(7000);
printf("%d,%d\n",addr.sin_family,addr.sin_port);
if(bind(s,(sockaddr*)&addr,sizeof(addr))==SOCKET_ERROR)
{
cout<<"Bind socket error:"<<GetLastError()<<endl;
return;
}
DWORD BytesRet;
//if(WSAIoctl(s,SIO_RCVALL,&InBuf,sizeof(InBuf),&OutBuf,sizeof(OutBuf),&BytesRet,NULL,NULL)==SOCKET_ERROR)
if(ioctlsocket(s,SIO_RCVALL,&BytesRet)==SOCKET_ERROR)
{
cout<<"WSAIoctl error"<<GetLastError()<<endl;
return;
}
}
char* RawSocket::GetRawPacket()
{ int BUF_SIZE=65535;
char *ret=new char[BUF_SIZE];
memset(ret,0,BUF_SIZE);
//printf("recv:%d\n",recv(s,ret,BUF_SIZE,0));
if(recv(s,ret,BUF_SIZE,0)==SOCKET_ERROR)
{
cout<<"another"<<endl;
cout<<"Recv error:"<<GetLastError()<<endl;
}
//printf("ret:%d\n",ret);
return ret;
}
class PacketDecode
{
public:
PacketDecode();
virtual ~PacketDecode();
public:
IP_HEADER *ih;
TCP_HEADER *th;
UDP_HEADER *uh;
char *data;
void DecodeInit(char*buf);
int GetProtocol();
int GetTotalLength();
char*GetRemoteIP();
char*GetLocateIP();
int GetSPort();
int GetDPort();
int GetIPHeadLen();
int GetTCPHeadLen();
int GetUDPHeadLen();
int GetICMPHeadLen();
char *GetData();
};
PacketDecode::PacketDecode()
{
data=new char[65536];
}
PacketDecode::~PacketDecode()
{
}
void PacketDecode::DecodeInit(char*buf)
{
data=buf;
//printf("buf:%d\n",buf);
ih=(IP_HEADER*)buf;
printf("ih:%d,\n",ih);
th=(TCP_HEADER*)(buf+GetIPHeadLen());
uh=(UDP_HEADER*)(buf+GetIPHeadLen());
}
int PacketDecode::GetIPHeadLen()
{
return ((ih->ver_ihl)&15)*4;//0x0f=00001111也就是取低4位,且IP包头是以4字节为单位的
}
int PacketDecode::GetProtocol()
{
return ih->proto;
}
int PacketDecode::GetTotalLength()
{
return ntohs(ih->total_len);
}
char *PacketDecode::GetLocateIP() //源IP地址
{
//inet_ntoa(*(in_addr*)&(ih->saddr));
//printf("\nsaddr:%d\n",ih->saddr);
return inet_ntoa(*(in_addr*)&(ih->saddr));
}
char *PacketDecode::GetRemoteIP() //目的地址(本机)
{
//printf("\ndaddr:%d\n",ih->daddr);
return inet_ntoa(*(in_addr*)&(ih->daddr));
}
int PacketDecode::GetSPort()
{
switch(GetProtocol())
{
case 17:
return ntohs(uh->sport);
break;
case 6:
return ntohs(th->sport);
break;
default:
return 0;
}
return 0;
}
int PacketDecode::GetDPort()
{
switch(GetProtocol())
{
case 17:
return ntohs(uh->dport);
break;
case 6:
return ntohs(th->dport);
break;
default:
return 0;
}
return 0;
}
int PacketDecode::GetTCPHeadLen()
{
return 20;
}
int PacketDecode::GetUDPHeadLen()
{
return 20;
}
int PacketDecode::GetICMPHeadLen()
{
return 20;
}
char*PacketDecode::GetData()
{
switch(GetProtocol())
{
case PROTO_TCP:
return data+GetIPHeadLen()+GetTCPHeadLen();
case PROTO_UDP:
return data+GetIPHeadLen()+GetUDPHeadLen();
case PROTO_ICMP:
return data+GetIPHeadLen();
}
}
struct node
{
char *a1;
char *a2;
int a3;
int a4;
int a5;
int a6;
int a7;
int a8;
int a9;
int a10;
char *a11;
};
void main()
{
RawSocket s;
PacketDecode p;
struct node n;
while(true)
{
s.NetInit();
s.GetIP(); //主机IP
printf("GetIP:%d\n",s.GetIP());
s.GetRawPacket();
printf("GRP:%ld\n",s.GetRawPacket());
p.DecodeInit(s.GetRawPacket());
n.a6=p.GetProtocol();
printf("PROTOCOL:%ld\n",n.a6);
n.a2=p.GetLocateIP();
printf("LocateIP:%ld\n",p.GetLocateIP());
n.a1=p.GetRemoteIP();
printf("RemoteIP:%ld\n",n.a1);
n.a3=p.GetDPort();
printf("Dport:%ld\n",n.a3);
n.a4=p.GetICMPHeadLen();
printf("ICMPHEADLEN:%ld\n",n.a4);
n.a5=p.GetIPHeadLen();
printf("IPHEADLEN:%ld\n",n.a5);
n.a7=p.GetSPort();
printf("SPROT:%ld\n",n.a7);
n.a8=p.GetTCPHeadLen();
printf("TCPHEADLEN:%ld\n",n.a8);
n.a9=p.GetTotalLength();
printf("TLENGTH:%ld\n",n.a9);
n.a10=p.GetUDPHeadLen();
printf("UDPHEADLEN:%ld\n",n.a10);
n.a11=p.GetData();
printf("DATA:%ld\n\n\n",n.a11);
}
}
多谢解答,谢谢
问题点数:20、回复次数:16Top
1 楼zhousqy(标准C匪徒)(甩拉,甩拉)回复于 2005-05-04 21:06:38 得分 0
瓦,这么长。Top
2 楼llf_hust()回复于 2005-05-04 21:07:41 得分 0
帮你UPTop
3 楼foochow(无聊,灌水......)回复于 2005-05-04 21:36:11 得分 0
UPTop
4 楼yuhjnm_20001(力)回复于 2005-05-04 22:52:37 得分 0
dingTop
5 楼ericqxg007(还有很多东西要学(卡卡一米阳光))回复于 2005-05-04 23:05:22 得分 0
~ ~
!Top
6 楼xuzheng318(忧郁王子)回复于 2005-05-05 00:38:06 得分 5
IP 数据报的格式
TCP/IP协议使用IP数据报包含一个数据报报头和一个数据区。
IP数据报头包含有源、目的信息,做寻径用。并且指明承载负载的协议类型。
数据报所携带的数据量不固定!下面给出IP数据报的详细格式:
0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7
-----------------------------------------------------------------|
版本 |报头长度| 服务类型 | 总长度 |
-----------------------------------------------------------------|
标识符 | 标志 | 分片偏移量 |
-----------------------------------------------------------------|
存活时间 | 协议 | 报头校验和 |
-----------------------------------------------------------------|
源地址 |
-----------------------------------------------------------------|
目的地址 |
-----------------------------------------------------------------|
IP选项 | 填充 |
-----------------------------------------------------------------|
数据区。。。 |
-----------------------------------------------------------------|
IP数据报的C语言结构:(不包含可选项和填充域)
/*The IP header for VC++ */
typedef struct tagipheader
{
unsigned char h_len:4;
unsigned char version:4;
unsigned char tos;
unsigned short total_len;
unsigned short ident;
unsigned char ttl;
unsigned char proto;
unsigned short checksum;
unsigned int sourceIP;
unsigned int destIP;
}IPHEADER;
2.1 版本协议号
IP数据报的第一个域是4bit长的版本域(version)。版本号规定了数据报的格式,
不同的IP协议版本其数据报格式有所不同。当前IP协议的版本号为4,称IPv4;下一
个将要发展的IP协议,版本号为6,即IPv6。
2.2 数据报的长度、填充域和总长度
报头长度域(h_len)也是4bit长.它指出报头的长度,如果报头的长度不是32bit的整数
倍,则由填充域添0补齐.
16bit长的数据报的总长域(total_len),它以字节为单位标定整个IP数据报的长度。
由于总长域占16bit,所以数据报最长可达2的16次方减1个字节。
2.3 服务类型和优先权
8bit长的服务类型域(tos)规定本数据报的处理方式,并分为5个子域,如图:
0 1 2 3 4 5 6 7
----------------------------------|
| 传输类型 |
优先权 |-------------------|
| D | T | R | C | |
----------------------------------|
3bit的优先级(precedence)子域指明本数据的优先级,允许发送方表示本数据报的重要
程度.其取值从0到7,0表示普通优先级,即网络控制优先级.大多数主机和路由器软件对此
不予理睬.
D、T、R、C位表示本数据报所期望的传输类型。取1时,D代表时延(Delay), T代表
高吞吐量(Throughput),R代表高可靠性(Reliability),C代表低开销。应注意每种网络
技术的D、T、R性能之间往往是此强彼弱的。应只指定其中一个!
2.4 标识符、标志和分片偏移量
网络数据最终都是通过物理网络帧传输,IP数据报也是!整个数据报被封装在一个物理
帧中传输时的效率最高。不同物理网络技术所采用的最大帧长是相异的。这个帧长称作为
最大传输单元(Maximum Transfer Unit,MTU).
当数据报分组从一个MTU较大的网络经路由器中继到一个MTU较小的网络上时,由于分组
过长,路由器就会拒绝中继或将数据报分片后再传送。分片通常在路由器中完成,而重组由
主机的IP协议完成。IP报头中的标识符(ident)、标志和分片偏移量(frag_and_flags)三个
域用作分片和重组控制.
标识符标识数据报发送的先后顺序,每产生一个新的数据报标识符增1,目的机用来重组分片
数据报.同一IP数据报分片后标识符域不变.
分片偏移量指完整的数据报内该分片的偏移量.
标志域有3个bit位组成,第一位保留为0,如图:
0 1 2
0 DF MF
DF位表示分组禁止被分片.MF位表示分组片未完.MF位清0,此分片是IP数据报分组的最后一片.
2.5 存活时间
存活时间(ttl)设置了该数据报在因特网中允许存在的最大生存时间,以秒为单位.每产生一个数据报时,就为它设置了一个最大的生存时间.当数据报通过的主机和路由器对该数据报进行处理时,又减去消耗的时间.一旦时间小于0,便将该数据报从因特网中删除,并向信源机发回错信息.
ttl保证了即使路由表不可靠而选择了一个循环路由,数据报都不会在因特网中无休止地流动.
2.6 协议序列号
协议域表示IP数据报中数据的协议类型,如TCP、UDP、ICMP等。下图列出了IANA已分配的常见协议序列号
十进制编号 关键字 协议名称
0 保留
1 ICMP 因特网控制报文协议
2 IGMP 因特网组管理协议
3 GGP 网关-网关协议
4 IP IP里的IP
5 ST 数据流
6 TCP 传输控制协议
8 EGP 外部网关协议
17 UDP 用户数据报协议
29 ISO-TP4 ISO传输协议类4
41~60 未分配
70 VISA VISA协议
80 ISO-IP ISO网间协议(CLNP)
88 IGRP 内部网关协议
89 OSPF 开放式最短路径优先协议
99~254 未分配
255 保留
2.7 源地址和目的地址
源IP地址(SourceIP)和目的IP地址(DestIP)域包含数据报的发送方和接受方的IP地址。Top
7 楼foxwing(穿过你的骨髓我的手)回复于 2005-05-05 01:09:07 得分 0
当套接字类型是SOCK_RAW时:
你调用了bind函数,也就是说61.149.185.201这个地址是本地的,那么你测试程序时在另一台机器上就必须指明以61.149.185.201作为目的地址。例如在另一台机器上用ping命令时,就必须这样:
ping 61.149.185.201
这样你的机器收到的就是来自于发出ping命令的那台机器的“询问”。
如果你的原意是只抓取来自61.149.185.201地址机器的数据(比如你向61.149.185.201发出ping命令,然后接收来自61.149.185.201的反馈),那么就不应该调用bind()函数,而应该调用connect()函数了。
之所以“源IP地址和目的IP地址老是一样的”,我想有两种可能,一种就是你在自己的机器(61.149.185.201)上ping自己的地址(61.149.185.201),这样源IP和目的IP自然是一样的。不过我想你不会犯这种低级错误。
第二种可能就是61.149.185.201这个地址是另外一台机器的地址,而你用bind()函数绑定别人的ip地址是什么意思呢?其结果就是相当于你根本没有调用bind(),而在不指定local address(通过bind函数)的情况下,不管网络上(仅限于你所处的局域网)正在传输的包是不是发送给你的,你都会“慷慨接纳”,无单也照收。而如果这个时候恰巧没人给你发送包,而你自己却在向外发送包的话,那么你就会只收到自己发送出去的包。于是,源IP和目的IP就一样了。
套接字类型SOCK_STREAM下的bind()函数和SOCK_RAW类型下的bind()函数行为是不一样的。Top
8 楼mostideal(三甲)回复于 2005-05-05 01:50:30 得分 0
studyTop
9 楼bubugo()回复于 2005-05-05 08:55:17 得分 0
foxwing 你好,多谢你回答我的问题。但是还有些不明白希望您指教
char *PacketDecode::GetLocateIP() //源IP地址
{
//inet_ntoa(*(in_addr*)&(ih->saddr));
//printf("\nsaddr:%d\n",ih->saddr);
return inet_ntoa(*(in_addr*)&(ih->saddr));
}
char *PacketDecode::GetRemoteIP() //目的地址(本机)
{
//printf("\ndaddr:%d\n",ih->daddr);
return inet_ntoa(*(in_addr*)&(ih->daddr));
}
中读出的ih->saddr是不同的,但是为什么return到Getlocate就和Remote一样了那?
而且我用sniffer和我的程序同时开除了源IP这一项其他的都是一样的,就是源IP老是不对。希望您指教,谢谢
Top
10 楼foxwing(穿过你的骨髓我的手)回复于 2005-05-05 17:11:41 得分 15
把main()函数中的
n.a2=p.GetLocateIP();
printf("LocateIP:%ld\n",p.GetLocateIP());
n.a1=p.GetRemoteIP();
printf("RemoteIP:%ld\n",n.a1);
改为:
n.a2=p.GetLocateIP();
printf("LocateIP:%s\n",p.GetLocateIP());
n.a1=p.GetRemoteIP();
printf("RemoteIP:%s\n",n.a1);
就正常了。
因为inet_ntoa()函数返回的是一个字符串。Top
11 楼foxwing(穿过你的骨髓我的手)回复于 2005-05-05 17:18:20 得分 0
不要随便使用强制转型。Top
12 楼bubugo()回复于 2005-05-06 07:05:01 得分 0
谢谢foxwing,真的学了不少东西。
多谢,^_^Top
13 楼bubugo()回复于 2005-05-06 07:26:01 得分 0
再请教一下:我的IP都文件定义是
typedef struct ip_header
{// IPv4 包头
unsigned char ver_ihl; // 版本 (4 bits) + 包头长度(4 bits)
unsigned char tos; // 服务类型
unsigned short total_len; // 数据包的总长度
unsigned short id; // ID号
unsigned short flag_offset; // 标志 (3 bits) + 分片偏移 (13 bits)
unsigned char ttl; // 生存时间
unsigned char proto; // 协议
unsigned short checksum; //校验
unsigned int saddr; // 源地址
unsigned int daddr; // 目的地址
unsigned int opt; //IP选项和填充
}IP_HEADER;
麻烦foxwing能不能帮我写个packetdecode中抓ttl,id ,和flag_offset的代码呢?
我写了写总是抓不出了,感激中,呵呵。谢谢Top
14 楼foxwing(穿过你的骨髓我的手)回复于 2005-05-06 20:09:17 得分 0
int PacketDecode::GetTTL()
{
int i;
i = (int)ih->ttl;
return i;
}
其它的函数都和这个差不多,我用ping命令测试过了,程序的结果和实际的TTL是一样的。
还有,你的main()函数里为什么不用cout呢?既然都用到类了,那为什么不用C++的iostream呢?Top
15 楼chd352622(Taiwan省委书记兼人大主任)回复于 2005-05-06 20:22:57 得分 0
gao shou a----Top
16 楼bubugo()回复于 2005-05-07 08:08:12 得分 0
呵呵,习惯了C语言了,有时就顺手写了,见笑了,多谢啦Top




