IP协议完整数据结构

一 IP协议

IP协议的完整数据结构为:以太网数据头 |  IP数据头 | TCP/UDP数据包头 | 数据

1.以太网头

#define ETHER_ADDR_LEN 			6  
//以太网数据头结构体,共14字节
typedef struct ether_header
{
	u_char ether_dhost[ETHER_ADDR_LEN];    	//目的MAC地址 6字节
	u_char ether_shost[ETHER_ADDR_LEN];   	//源MAC地址 6字节
	u_short ether_type;         			//上一层协议类型,如0x0800代表上一层是IP协议,0x0806为arp  2字节
}ether_header;

2.IP首部

/* IP 首部  24byte*/
typedef struct ip_header{
#if __BYTE_ORDER == __LITTLE_ENDIAN 
	u_char  ihl:4;			// IP数据头的总长度/4(4 bits)
	u_char  version:4;		// 版本 (4 bits) 用来表明IP协议实现的版本号,当前一般为IPv4,即0100
#elif __BYTE_ORDER == __BIG_ENDIAN 
	u_char  version:4;		// 版本 (4 bits) 用来表明IP协议实现的版本号,当前一般为IPv4,即0100
	u_char  ihl:4;			// IP数据头的总长度/4(4 bits)
#endif
	u_char  tos;            // 服务类型(Type of service) 
	u_short tlen;           // 整个IP数据包长度 (IP数据头 | UDP数据包头 | 数据)(Total length) 
	u_short identification; // 标识(Identification)
	u_short flags_fo;       // 标志位(Flags) (3 bits) + 段偏移量(Fragment offset) (13 bits)
	u_char  ttl;            // 存活时间(Time to live)
	u_char  proto;          // 协议(Protocol)
	u_short crc;            // 首部校验和(Header checksum)
	u_int   saddr;			// 源地址(Source address)
	u_int   daddr;			// 目的地址(Destination address)
	u_int   op_pad;         // 选项与填充(Option + Padding)
}ip_header;

3.TCP/UDP首部

/* TCP 首部  20byte*/
typedef struct tcp_header{
	u_short sport; /* 源端口 */
	u_short dport; /* 目的端口 */
	u_int   seq;  /* 序列号 */
	u_int   ack;  /* 确认序列号 */
#if __BYTE_ORDER == __LITTLE_ENDIAN 
	u_char reserved_1:4; //保留6位中的4位首部长度
	u_char thl:4;    //tcp头部长度
	u_char flag:6;    //6位标志
	u_char reseverd_2:2; //保留6位中的2位
#elif __BYTE_ORDER == __BIG_ENDIAN 
	u_char thl:4;    //tcp头部长度
	u_char reserved_1:4; //保留6位中的4位首部长度
	u_char reseverd_2:2; //保留6位中的2位
	u_char flag:6;    //6位标志 
#endif

	u_short windows;  /* 16位窗口大小 */
	u_short chksum;   /* 校验和 */
	u_short urgentpt; /* 紧急数据偏移量指针 */
}tcp_header;

/* UDP 首部 8*/
typedef struct udp_header{
	u_short sport;          // 源端口(Source port)
	u_short dport;          // 目的端口(Destination port)
	u_short len;            // UDP数据包长度(Datagram length)
	u_short crc;            // 校验和(IP为首部 | UDP数据包头 | 数据), 这个比较特殊一点, 要加一个伪首部)(Checksum)
}udp_header;

4.伪首部

/* 伪首部*/
typedef struct tsd_header {
	ULONG sourceip; //源IP地址
	ULONG destip; //目的IP地址
	BYTE mbz; //置空(0)
	BYTE ptcl; //协议类型
	USHORT plen; //TCP/UDP数据包的长度(即从TCP/UDP报头算起到数据包结束的长度 单位:字节) 和UDP长度是一样的
}tsd_header;

二 创建一个完整的IP协议包

int size;//用户数据大小
char *buff=new char[size];//用户数据

u_char ptcl;
//计算tcp/udp首部大小
if (ptcl==IPPROTO_UDP)
    headersz=sizeof(udp_header);
else if (ptcl==IPPROTO_TCP)
	headersz= sizeof(tcp_header);
    
//计算整个数据包大小
int packetsz=sizeof(ether_header) + sizeof(ip_header)+headersz+size;

//创建IP协议包buffer
char* buffer=new char[packetsz+1];

//插入以太网头部
ether_header* pether_header =   (ether_header*)buffer; 
//插入ip头部 
ip_header* pip_herder       =   (ip_header*)(buffer + sizeof(ether_header));

//插入tcp/udp头部
udp_header* pudp_herder;
tcp_header* ptcp_herder;
if (ptcl==IPPROTO_UDP)
		pudp_herder         =   (udp_header*)(buffer + sizeof(ether_header) + sizeof(ip_header));  
	else if(ptcl==IPPROTO_TCP)
		ptcp_herder         =   (tcp_header*)(buffer + sizeof(ether_header) + sizeof(ip_header)); 

//插入用户数据
int tsize=sizeof(ether_header) + sizeof(ip_header) + headersz;
for(int i=tsize;i<packetsz;i++)
{
		buffer[i]=buff[i-tsize];
}

//构建以太网首部 (MAC地址根据实际情况来)
pether_header->ether_dhost[0] = 1;        
pether_header->ether_dhost[1] = 1;        
pether_header->ether_dhost[2] = 1;       
pether_header->ether_dhost[3] = 1;      
pether_header->ether_dhost[4] = 1;        
pether_header->ether_dhost[5] = 1;      
pether_header->ether_shost[0] = 1;      
pether_header->ether_shost[1] = 1;        
pether_header->ether_shost[2] = 1;       
pether_header->ether_shost[3] = 1;      
pether_header->ether_shost[4] = 1;        
pether_header->ether_shost[5] = 1;    
pether_header->ether_type = htons(ETHERTYPE_IP);  

//构建IP数据头  
if((sizeof(ip_header) % 4) != 0)  
{  
	TRACE("[IP Header error]\n");  
}
pip_herder->ihl = sizeof(ip_header) / 4;  
pip_herder->version = 4;  
pip_herder->tos = 0;  
pip_herder->tlen = htons(sizeof(buffer) - sizeof(ether_header));  
pip_herder->identification = htons(0x1000);  
pip_herder->flags_fo = htons(0);  
pip_herder->ttl = 0x80;  
pip_herder->proto = ptcl;  
pip_herder->crc = 0;  
pip_herder->saddr = inet_addr(vnetcardinfo[addevidx].szIpAddress);  
pip_herder->daddr = inet_addr(addr);  
pip_herder->crc  = in_cksum((u_int16_t*)pip_herder, sizeof(ip_header));   


if (ptcl==IPPROTO_UDP)
{
     //构建UDP数据头; 
	pudp_herder->dport = htons(sport);  
	pudp_herder->sport = htons(dport);  
	pudp_herder->len = htons(sizeof(buffer) - sizeof(ether_header) - sizeof(ip_header));  
	pudp_herder->crc = 0;  
}
else if (ptcl==IPPROTO_TCP)
{
	//构建TCP数据头
	ptcp_herder->sport =htons(sport);
	ptcp_herder->dport = htons(dport); 
	ptcp_herder->seq=0; 
	ptcp_herder->ack=0;  
	ptcp_herder->thl=sizeof(tcp_header)/4; 
	ptcp_herder->flag =1;   
	ptcp_herder->windows=htons(512); 
	ptcp_herder->chksum=0;   
	ptcp_herder->urgentpt=0; 
}

//计算校验和
u_char *buffer2= new u_char[headersz+sizeof(tsd_header)+1] ; 
tsd_header tsd;
tsd.sourceip = pip_herder->saddr;  
tsd.destip = pip_herder->daddr;  
tsd.ptcl = ptcl;
tsd.plen =  htons(headersz);  
tsd.mbz = 0;  
memcpy( buffer2, &tsd, sizeof(tsd_header) ); 
if (ptcl==IPPROTO_UDP)
{
	memcpy( buffer2 + sizeof(tsd_header), &pudp_herder, sizeof(udp_header) );
	pudp_herder->crc = in_cksum( (unsigned short *)buffer2, sizeof(tsd_header) + headersz +1 ); 
}
else if (ptcl==IPPROTO_TCP)
{
	memcpy( buffer2 + sizeof(tsd_header), &ptcp_herder, sizeof(udp_header) );
	ptcp_herder->chksum= in_cksum( (unsigned short *)buffer2, sizeof(tsd_header) + headersz +1 ); 
}
delete[] buffer2;

delete[] buffer;

附加:计算校验值的函数

u_int16_t in_cksum (u_int16_t * addr, int len)  
{  
    int     nleft = len;  
    u_int32_t sum = 0;  
    u_int16_t *w = addr;  
    u_int16_t answer = 0;  
  
    /* 
    * Our algorithm is simple, using a 32 bit accumulator (sum), we add 
    * sequential 16 bit words to it, and at the end, fold back all the 
    * carry bits from the top 16 bits into the lower 16 bits. 
    */  
    while (nleft > 1) {  
        sum += *w++;  
        nleft -= 2;  
    }  
    /* mop up an odd byte, if necessary */  
    if (nleft == 1) {  
        * (unsigned char *) (&answer) = * (unsigned char *) w;  
        sum += answer;  
    }  
  
    /* add back carry outs from top 16 bits to low 16 bits */  
    sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */  
    sum += (sum >> 16);     /* add carry */  
    answer = ~sum;     /* truncate to 16 bits */  
    return (answer);  
}  

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值