一、IP、UDP校验和
1.1 计算原理
IP校验和只校验 IP头部。
UDP校验和校验 UDP头部和UDP数据部分。
TCP校验和校验 TCP头部和TCP数据部分。
计算原理:
1. 将所有位划分为16位(2字节)的字。
2. 将所有16位的字相加,得到一个32位的字。
3. 将32位字的高16位与低16位相加,直到高16位全部为0。得到一个16位的字。
4. 将3中得到的字,取反即为校验和。
1.2 代码
#include <iostream> #include <WinSock2.h> //struct in_addr using namespace std; #pragma comment(lib,"Ws2_32.lib") unsigned short ip_cksum(unsigned short *buf, int len) { //将每个16bit求和,和为32bit unsigned int sum = 0; while (len > 1) { sum += *buf++; len -= 2; } //若长度为奇数字节,后面补0 if(1 == len) { sum += *(unsigned char*)buf; } //将和32bit中,高16bit与低16bit相加,直到只有16bit while(sum>>16) { sum = (sum>>16) + (sum&0xffff); } //取反 return ~sum; } unsigned short udp_cksum(unsigned int saddr, unsigned int daddr, unsigned short *buf, int len) { struct pseudo_hdr { struct in_addr src; struct in_addr dst; unsigned char proto; unsigned char mbz; //proto和mbz的先后顺序很重要,决定着是0x0011,还是0x1100 unsigned short len; }; unsigned char raw_buf[1024]; struct pseudo_hdr *ph = (struct pseudo_hdr*)raw_buf; ph->src.s_addr = htonl(saddr); ph->dst.s_addr = htonl(daddr); ph->proto = IPPROTO_UDP; ph->mbz = 0; ph->len = len; int ph_len = sizeof(struct pseudo_hdr); memcpy(raw_buf + ph_len, buf, len); return ip_cksum((unsigned short*)raw_buf, ph_len + len); } void main() { cout.setf(ios::showbase); //ip check sum unsigned short iph[] = {0x4500, 0x003e, 0x4bd9, 0x0000, 0x4011, 0x000, 0xc0a8, 0x1a73, 0xc0a8, 0x1a75}; //0x789d unsigned short cksum = ip_cksum(iph, 20); cout<<"ip cksum: "<<hex<<cksum<<endl; iph[3] = cksum; cksum = ip_cksum(iph, 20); if(0 == cksum) cout<<"ip check sum is correct."<<endl; else cout<<"ip check sum is incorrect."<<endl; //udp check sum unsigned int saddr = inet_addr("192.168.26.115"); unsigned int daddr = inet_addr("192.168.26.117"); unsigned short udph[42] = {0xa0a9, 0x0035, 0x002a, 0x0000, 0xb5b7, 0x0100, 0x0001, 0x0000, 0x0000, 0x0000, 0x0377, 0x7777, 0x0967, 0x756f, 0x7765, 0x6e79, 0x616e, 0x0263, 0x6e00, 0x0001, 0x0001}; //0x4052 cksum = udp_cksum(saddr, daddr, udph, 42); cout<<"udp cksum: "<<hex<<cksum<<endl; udph[3] = cksum; cksum = udp_cksum(saddr, daddr, udph, 42); if(0 == cksum) cout<<"udp check sum is correct."<<endl; else cout<<"udp check sum is incorrect."<<endl; }
1.3 输出结果
参考资料:
如何计算UDP/TCP校验和checksum:http://hi.baidu.com/1981zb/item/4e130a20c4dd50cedcf69aaf
UDP计算校验和:http://blog.csdn.net/maeom/article/details/6065203
二、判断IP地址
1.1 判断原理
注释了的代码为在Linux内核中使用的判断代码。
判断原理:
1. 判断是否包含3个点号“.”;
2. 以点号"."拆分字符串,判断各个串是否为数字,并且在0~255之间。
1.2 代码
#include <iostream> using namespace std; /////////////////////////////////////////////////// // //used in linux kernel code. // /////////////////////////////////////////////////// /* int check_is_ipnum(char **num, const char* sz) { char *p, *pt; char *after; assert(NULL != num); assert(NULL != *num); if (NULL == num || NULL == *num) { if (NULL == num) LOG_DEBUG("num is NULL.\n"); else if (NULL == *num) LOG_DEBUG("*num is NULL.\n"); return -1; } if (NULL == (pt = p = strsep(num, sz))) { LOG_DEBUG("check_is_ipnum error, strsep(). num:%s, p:%s\n", *num, p); return -2; } do { if (!isdigit(*pt)) { LOG_DEBUG("check_is_ipnum error, isdigit(). num:%s, p:%s\n", *num, pt); return -3; } ++pt; }while(pt && ('\0' != *pt)); return simple_strtoul(p, &after, 0); } int check_is_ip(char *ip) { char temp_ip[20]; int count; int i; int ipnum; char *pt; assert(NULL != ip); //ARG: IN if (NULL == ip) { LOG_DEBUG("ip is NULL.\n"); return -1; } memset(temp_ip, 0, 20); strcpy(temp_ip, ip); // count = 0; for (i=0; i<strlen(ip); ++i) { if ('.' == temp_ip[i]) { ++count; } } if (3 != count) { LOG_DEBUG("ip is error, ip:%s\n", ip); return -2; } // pt = temp_ip; ipnum = check_is_ipnum(&pt, "."); if (ipnum < 0 || ipnum > 255) { LOG_DEBUG("the first num of ip is error.ip:%s", ip); return -3; } ipnum = check_is_ipnum(&pt, "."); if (ipnum < 0 || ipnum > 255) { LOG_DEBUG("the second num of ip is error.ip:%s", ip); return -4; } ipnum = check_is_ipnum(&pt, "."); if (ipnum < 0 || ipnum > 255) { LOG_DEBUG("the third num of ip is error.ip:%s", ip); return -5; } ipnum = check_is_ipnum(&pt, "."); if (ipnum < 0 || ipnum > 255) { LOG_DEBUG("the fourth num of ip is error.ip:%s", ip); return -6; } return 0; } */ int check_is_ipnum(char *num, const char* sz) { char *p, *pt; if (NULL == (pt = p = strtok(num, sz))) return -2; do { if (!isdigit(*pt)) return -3; ++pt; } while (pt && ('\0' != *pt)); return atol(p); } bool check_is_ip(char *ip) { if(NULL == ip) return false; char temp_ip[20] = {0}; strcpy(temp_ip, ip); //是否有3个点号"." int count = 0; for (int i=0; i<strlen(ip); ++i) { if ('.' == temp_ip[i]) { ++count; } } if (3 != count) return false; //以点号"."拆分数值,然后判断每个数值是否合法 int ipnum = check_is_ipnum(temp_ip, "."); if (ipnum < 0 || ipnum > 255) return false; ipnum = check_is_ipnum(NULL, "."); if (ipnum < 0 || ipnum > 255) return false; ipnum = check_is_ipnum(NULL, "."); if (ipnum < 0 || ipnum > 255) return false; ipnum = check_is_ipnum(NULL, "."); if (ipnum < 0 || ipnum > 255) return false; return true; } void main() { char *ip = "192.168.10.234"; if(check_is_ip(ip)) cout<<ip<<" is a ip."<<endl; else cout<<ip<<" is not a ip."<<endl; }