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