一 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);
}