Golang Go语言中darwin/amd64平台解析IP Packet Header得到的报文长度错误

发布于 1周前 作者 caililin 来自 Go语言

Golang Go语言中darwin/amd64平台解析IP Packet Header得到的报文长度错误

直接贴代码,这是从 198.18.255.1 Ping 8.8.8.8(原始 IP 不是这个)返回的 IP 报文:

package main

import (
	"encoding/binary"
	"fmt"
	"golang.org/x/net/ipv4"
)

func main() {

	// https://en.wikipedia.org/wiki/IPv4#Total_Length
	var hdrBytes = []byte{
		69, 0, // Version |	IHL	| DSCP	| ECN
		0, 84, // Total_Length
		125, 47, // Identification
		0, 0, // Flags | Fragment Offset
		63,      // Time To Live
		1,       // Protocol
		85, 169, // Header Checksum
		8, 8, 8, 8, // Source IP Address
		198, 18, 255, 1, //Destination IP Address
	}
	header, err := ipv4.ParseHeader(hdrBytes)
	if err != nil {
		fmt.Printf("Parse failed. err: %v\n", err)
	}
	fmt.Printf("header: %v\n", header)
	fmt.Printf("header.TotalLen: %d\n", header.TotalLen)

	realTotalLen := binary.BigEndian.Uint16(hdrBytes[2:4])
	fmt.Printf("realTotalLen: %d\n", realTotalLen)

	totalLenByBigEndian := binary.BigEndian.Uint16(hdrBytes[2:4])
	fmt.Printf("totalLenByBigEndian: %d\n", totalLenByBigEndian)

	totalLenByLittleEndian := binary.LittleEndian.Uint16(hdrBytes[2:4])
	fmt.Printf("totalLenByLittleEndian: %d\n", totalLenByLittleEndian)

}

这段是解析 IP 报文 Header 的代码,在 Linux 和 Windows 执行得到的 header.TotalLen 都是 84,但是 darwin/amd64 就是 21524 。

按照相关规范,IP 报文 Header 字段均以大端序包装。这个看起来在 darwin 用了小端序解析。但是就算用小端序,这个值也应该是 21504 。

看 Go 解析的代码,原来还在解析时加上了 hdrlen 自身的 20 长度,这个似乎有点问题。我不了解那么多关于平台相关的,但是网络 IP 报文应该和平台无关吧。


	switch runtime.GOOS {
	case "darwin", "ios", "dragonfly", "netbsd":
		h.TotalLen = int(socket.NativeEndian.Uint16(b[2:4])) + hdrlen # 这里加了 Header 长度
		h.FragOff = int(socket.NativeEndian.Uint16(b[6:8]))
	case "freebsd":
		if freebsdVersion < 1100000 {
			h.TotalLen = int(socket.NativeEndian.Uint16(b[2:4]))
			if freebsdVersion < 1000000 {
				h.TotalLen += hdrlen
			}
			h.FragOff = int(socket.NativeEndian.Uint16(b[6:8]))
		} else {
			h.TotalLen = int(binary.BigEndian.Uint16(b[2:4]))
			h.FragOff = int(binary.BigEndian.Uint16(b[6:8]))
		}
	default:
		h.TotalLen = int(binary.BigEndian.Uint16(b[2:4]))
		h.FragOff = int(binary.BigEndian.Uint16(b[6:8]))
	}

然后 2 年前就有人提出这个问题了,但是还是没人修复。难道没人用 Mac 做 TCP/IP 网络编程吗。

Ref: https://github.com/golang/go/issues/32118


更多关于Golang Go语言中darwin/amd64平台解析IP Packet Header得到的报文长度错误的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html

回到顶部