现在的位置: 首页 > 综合 > 正文

常用:计算IP、UDP校验和、判断合法IP地址

2018年10月03日 ⁄ 综合 ⁄ 共 4417字 ⁄ 字号 评论关闭

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

抱歉!评论已关闭.