一、ip校验和的计算:
计算方法:
1. ip包头(共20个字节)按照每16个bit作为一个值依次进行相加
2. 将计算结果的进位加到低16位上
3. 将结果取反
ip包头的内存内容
eg:
45 00 00 20 0F B8 00 00
80 11 00 00 C0 A8 0A 9F
C0 A8 0A C7
将 0x4500 0x0020 0x0FB8 0x0000 0x8011 0x0000 0xC0A8 0x0A9F 0xC0A8 0x0AC7 依次相加 所得结果为0x26B9F 然后将 0x0002 + 0x6B9F = 0x6BA1
然后将 0x6BA1 取反得 0x945E
要注意两点:
1 在给ip_header计算校验和之前 首先把ip_header的checksum字段置为0
2 计算得到checksum之后 赋值时要转换为网络字节序:
ip_header.checksum = htons(checksum);
struct ip_header
{
unsigned char ihl:4;
unsigned char version:4;
u_char tos;
u_short tot_len;
u_short id;
u_short frag_off;
u_char ttl;
u_char protocol;
u_short check;
u_int saddr;
u_int daddr;
};
u_short get_ip_checksum(char* ip_hdr)
{
char* ptr_data = ip_hdr;
u_long tmp = 0;
u_long sum = 0;
for (int i=0; i<20; i+=2)
{
tmp += (u_char)ptr_data[i] << 8;
tmp += (u_char)ptr_data[i+1];
sum += tmp;
tmp = 0;
}
u_short lWord = sum & 0x0000FFFF;
u_short hWord = sum >> 16;
u_short checksum = lWord + hWord;
checksum = ~checksum;
return checksum;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
二、udp校验和
typedef struct udp_check_subhdr
byte目的ip地址 + 0x00 + 1 byte协议 + UDP 长度(2byte)
{
u_long src_ip;
u_long dst_ip;
char mbz;
char protocol;
u_short len;
} udp_check_subhdr;
u_short get_udp_checksum(char* pudp_pkt, int pkt_len)
{
ether_header *eth_hdr = (ether_header *)pudp_pkt;
ip_header *ip_hdr = (ip_header*)( pudp_pkt+sizeof(ether_header) );
udphdr *udp_hdr = (udphdr*)( (char*)ip_hdr+sizeof(ip_header) );
u_short udp_part_len = pkt_len-sizeof(ether_header)-sizeof(ip_header);
udp_check_subhdr udp_subhdr;
udp_subhdr.protocol = ip_hdr->protocol;
udp_subhdr.dst_ip = ip_hdr->daddr;
udp_subhdr.src_ip = ip_hdr->saddr;
udp_subhdr.mbz = 0x00;
udp_subhdr.len = htons(udp_part_len);
int subhdr_len = sizeof(udp_check_subhdr);
int buf_size = udp_part_len + subhdr_len;
if (pkt_len < buf_size)
return 0;
u_char* buffer = (u_char*)malloc(buf_size);
memset(buffer, 0x00, buf_size);
memcpy(buffer, (char*)&udp_subhdr, subhdr_len);
memcpy(buffer + subhdr_len, (char*)udp_hdr, udp_part_len);
unsigned char* ptr_data = buffer;
u_long tmp = 0;
u_long sum = 0;
for (int i=0; i<buf_size; i+=2)
{
tmp += (u_char)ptr_data[i] << 8;
tmp += (u_char)ptr_data[i+1];
sum += tmp;
tmp = 0;
}
u_short lWord = sum & 0x0000FFFF;
u_short hWord = sum >> 16;
u_short checksum = lWord + hWord;
checksum = ~checksum;
return checksum;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
最后: ip校验和还有udp校验和的查看是在接收端查看的,从源端查看是没有计算的值(ip校验和是0x00 udp校验和不清楚什么意义) 用pcap发送自定义数据包时 调用pcap_sendpacket时是直接发送定义好的数据包 就是将定义好的包直接通过网卡发送 不会经过电脑上的ip层和链路层 所以 校验和要自己计算
从两个网页处学到计算方法:
http://www.360doc.com/content/12/0511/15/621500_210332306.shtml
http://blog.csdn.net/maeom/article/details/6065203
*注: 仅作为笔记之用 如有错误或不妥之处还望指正。