您现在的位置是:首页 > 正文

【golang基础】校验和计算

2024-02-01 03:01:38阅读 2
首先,IP、ICMP、UDP和TCP报文头都有检验和字段,大小都是16bit,算法基本上也是一样的。
在发送数据时,为了计算数据包的检验和。应该按如下步骤:
1、把校验和字段设置为0;
2、把需要校验的数据看成以16位为单位的数子组成,依次进行二进制反码求和;
3、把得到的结果存入校验和字段中
在接收数据时,计算数据包的检验和相对简单,按如下步骤:
1、把首部看成以16位为单位的数字组成,依次进行二进制反码求和,包括校验和字段;
2、检查计算出的校验和的结果是否为0;
3、如果等于0,说明被整除,校验和正确。否则,校验和就是错误的,协议栈要抛弃这个数据包。

虽然说上面四种报文的校验和算法一样,但是在作用范围存在不同:IP校验和只校验20字节的IP报头;而ICMP校验和覆盖整个报文(ICMP报头+ICMP数据);UDP和TCP校验和不仅覆盖整个报文,而且还有12个字节的IP伪首部,包括源IP地址(4字节)、目的IP地址(4字节)、协议(2字节)、TCP/UDP包长(2字节)。另外UDP、TCP数据报的长度可以为奇数字节,所以在计算校验和时需要在最后增加填充字节0(填充字节只是为了计算校验和,可以不被传送)。

package main

import (
	"fmt"
	"encoding/hex"
)

func IPv4CheckSum(data []byte) uint16 {
	var (
		sum    uint32
		length int = len(data)
		index  int
	)
	//以每16位为单位进行求和,直到所有的字节全部求完或者只剩下一个8位字节(如果剩余一个8位字节说明字节数为奇数个)
	for length > 1 {
		sum += uint32(data[index])<<8 + uint32(data[index+1])
		index += 2
		length -= 2
	}
	//如果字节数为奇数个,要加上最后剩下的那个8位字节
	if length > 0 {
		sum += uint32(data[index])
	}
	//加上高16位进位的部分
	sum += (sum >> 16)
	//别忘了返回的时候先求反
	return uint16(^sum)
}

func main() {
	//ipv4的checksum在第10字节开始
	//str := "4500002831c840008006952dc0a8d901c0a8d987" //校验和952d
	//str := "4500002831c8400080060000c0a8d901c0a8d987"
	str := "4500005831cd400080060000c0a8d901c0a8d987"   //94f8
	b, _ := hex.DecodeString(str)

	encodedStr := hex.EncodeToString(b)
	fmt.Printf(" bytes-->%02x \n", b)
	fmt.Printf("string-->%s \n", encodedStr)

	ret := IPv4CheckSum(b)
	fmt.Printf("ret:%x \n", ret)
}

运行结果:
[root@localhost]# go run checksum.go
bytes–>4500005831cd400080060000c0a8d901c0a8d987
string–>4500005831cd400080060000c0a8d901c0a8d987
ret:94f8

针对ipv4和ipv6的校验和计算,可以参考nff-go的checksum.go。
ipv6校验和计算,linux内核参考:__sum16 csum_ipv6_magic(const struct in6_addr *saddr,const struct in6_addr *daddr,__u32 len, __u8 proto, __wsum csum)。

网站文章

  • 栈基础操作1--顺序栈的实现

    //top指针指的是一个空格 #include&quot;pch.h&quot; #include #define MaxSize 200//顺序栈最大长度 using namespace std; typedef int SElemType;//数据类型 typedef struct { SElemType *base;//栈底 SElemType *top;//栈顶 in...

    2024-02-01 03:01:31
  • Solr配置停止词/排除词 stopwords(mmseg版)

    Solr配置停止词/排除词 stopwords(mmseg版)

    停止词是无功能意义的词,比如is 、a 、are 、”的”,“得”,“我” 等,这些词会在句子中多次出现却无意义,所以在分词的时候需要把这些词过滤掉。 测试于:Solr 4.5.1, mmseg4j 1.9.1, Jdk 1.6.0_45, Tomcat 6.0.37 | CentOS 5.7 我这里拿名为test的core做例子。 准备停止词 在solr home下建dic目录,

    2024-02-01 03:01:24
  • Flutter路由跳转父级页面向子页面传参及子页面向父级页面传参

    Flutter路由跳转父级页面向子页面传参及子页面向父级页面传参

    Flutter中页面通过路由跳转传参主要分两种,一种是通过push()跳转时根据设定的参数进行传参,另一种是通过pop()返回时进行传参。父级页面向子页面push()传参假设从A页面跳到B页面可能需要携带参数userName和userAge这两个参数,那么需要在B页面先设置这两个参数名;假设userName必须填而userAge非必需,那么可以通过设置@required其为必填选项:...

    2024-02-01 03:01:19
  • 具体说一下Python编码的来源和使用方法

    Python编码来源于Guido van Rossum,是一种高级编程语言,可以用来开发网站、网络服务、后台应用程序和软件等。使用Python编码的方法是先安装Python编程环境,然后使用编译器和解释器来编写、编译、执行和调试Python代码,最后在Python解释器中运行程序。...

    2024-02-01 03:00:52
  • STM32常见错误

    一、 在“Debug选项卡”下设置好仿真器的类型后,下载程序时却提示“No ULINK Device found.”    解决办法: Keil MDK默认使用ULINK仿真器下载程序,在“Utilities选项卡”下把编程所使用的仿真器改为相应的类型即可。 二、 编译工程时提示如下信息: main.axf: Error: L6218E: Undefined symbol

    2024-02-01 03:00:44
  • sql server中的存储过程调试

    调试: 在SQL QUERY中—》对象浏览器—》存储过程—》选择要调试的存储过程—》右击—》选择调试(debug)—》输入参数—》--设置完你的参数值后--点击执行,就是出现一个浮动工具条,上面有单步执行,断点设置等 ---跟踪 : 开始-&gt;程序-&gt;MS SQLSERVER-&gt;事件探查器(SQL Profiler)--&gt;文件--&gt;新建--&gt;跟踪就可以...

    2024-02-01 03:00:39
  • error LNK2005: 找到一个或多个多重定义的符号已经在xxxx.obj中定义的解决方法

    总结一下,当我们在进行C/C++编程时,如果出现error LNK2005错误提示&quot;找到一个或多个多重定义的符号已经在xxxx.obj中定义&quot;时,通常表示在多个源文件中定义了相同的...

    2024-02-01 02:59:52
  • 【题解】UVA1252:Twenty Questions

    @vjudge 状压 可以这样设计状态 dfs(s,a)dfs(s,a)dfs(s,a)表示当前已经猜测的集合,目前还没有确定的数在sss集合里面的共同特征为aaa,还要猜几次 枚举下一次猜的位为kk...

    2024-02-01 02:59:43
  • 什么是loadsh

    什么是loadsh这个概念真不知道?但是如果你说防抖和节流那是必须知道,用别的名字我反而不知是何东东。js call、apply、bind_如花菇凉的博客-CSDN博客================...

    2024-02-01 02:59:34
  • 防止表单重复提交

    比如在购物网站支付的时候,就要避免表单重复提交。解决这个问题,可以从两个方面考虑。(1)前端a.提交之后,利用js将提交按钮禁用掉。b.提交之后,在一个新标签页打开一个页面,也就是用户的当前页面已经不再是提交页面了。(2)后端a。在提交页中隐藏一个字段值,然后在后端页面中,根据这个值来判断是否已经提交过了。b。利用数据库来防止重复提交。例如,购物账单,付款之后,会往数据

    2024-02-01 02:59:00