Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

在charpter 3 中 Ping 代码有问题,具体问题,把代码弄来跑一下就知道了,但是我想咨询各位大佬另外一个问题 #42

Open
alpha-baby opened this issue Dec 26, 2020 · 1 comment

Comments

@alpha-baby
Copy link

下列代码是我copy的 Ping 那个demo然后做了一些修改而成

这代码我在本地的mac上跑是有问题的, 但是在linux上跑就是正确的:

mac 系统版本为 1.15.5
go 版本为 1.13.8 和 1.15.5 都试过

原文在: https://github.com/astaxie/NPWG_zh/blob/master/zh/Text/chapter-socket.html 的最底部

package basic

import (
	"fmt"
	"net"
	"os"
	"time"
	"encoding/hex"
)

func Ping() {
	if len(os.Args) != 2 {
		fmt.Println("Usage: ", os.Args[0], "host")
		os.Exit(1)
	}

	addr, err := net.ResolveIPAddr("ip", os.Args[1])
	if err != nil {
		fmt.Println("Resolution error", err.Error())
		os.Exit(1)
	}

	var localAddr *net.IPAddr
	if localAddr == nil {
		conn, err := net.Dial("tcp", "www.baidu.com:80")
		checkError(err)

		localAddr, err = net.ResolveIPAddr("ip4", conn.LocalAddr().(*net.TCPAddr).IP.String())
		checkError(err)
	}

	conn, err := net.DialIP("ip4:icmp", localAddr, addr)
	checkError(err)

	var msg [512]byte
	msg[0] = 8  // echo
	msg[1] = 0  // code 0
	msg[2] = 0  // checksum, fix later
	msg[3] = 0  // checksum, fix later
	msg[4] = 0  // identifier[0]
	msg[5] = 13 //identifier[1]
	msg[6] = 0  // sequence[0]
	msg[7] = 37 // sequence[1]
	length := 8

	check := CheckSum(msg[0:length])
	msg[2] = byte(check >> 8)
	msg[3] = byte(check & 255)
	startTime := time.Now()
	_, err = conn.Write(msg[0:length])
	checkError(err)

	n, err := conn.Read(msg[0:])
	checkError(err)
	fmt.Printf("raw ip msg: %v \n", hex.EncodeToString(msg[:n]))
	endTime := time.Now()
	result := make([]byte, n)
	if n > 20 {
		result = msg[20:]
	}

	fmt.Println("Got response")
	if result[5] == 13 {
		fmt.Println("identifier matches")
	}
	if result[7] == 37 {
		fmt.Println("Sequence matches")
	}
	fmt.Println("ip packet: ", msg[:n], "length: ", n)
	ipHeadLength := int(msg[0]) & 15 * 4
	fmt.Printf("ip header length: %v \n", ipHeadLength)
	fmt.Printf("ip len %x %x \n", msg[2], msg[3]) // 重点在这里,我发现在mac系统上,我用wirshark 抓包抓到的数据和这里读到的数据是不一样的
	totalLength := int(msg[2])<<8 + int(msg[3])
	fmt.Printf("ip total length: %v \n", totalLength)
	ipDataLength := totalLength - ipHeadLength
	fmt.Println("icmp packet: ", result[:ipDataLength])
	t := endTime.Sub(startTime)
	fmt.Printf("time: %.3f ms\n", float64(t.Microseconds())/1000)
}

// 原文中的计算校验和的代码是有问题的,这里我换成了另外的,这个函数是没有问题的
func CheckSum(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)
}

这是代码获取到的IP 报文的结果:

=== RUN   TestPing
host:  [103.235.46.39]
raw ip msg: 4500080038c700002f01103e279c454f0a01cbf00000ffcd000d0025
Got response
identifier matches
Sequence matches
ip packet:  [69 0 8 0 56 199 0 0 47 1 16 62 39 156 69 79 10 1 203 240 0 0 255 205 0 13 0 37] length:  28
ip header length: 20
ip len 8 0
ip total length: 2048
--- FAIL: TestPing (0.36s)
panic: runtime error: slice bounds out of range [:2028] with capacity 492 [recovered]
	panic: runtime error: slice bounds out of range [:2028] with capacity 492

用wirshark 抓到的包: IP包 起始位置为第一行的: 45 00

0000   00 e0 4c 6b 10 e0 3c f5 cc 71 88 01 08 00 45 00
0010   00 1c 38 c7 00 00 2f 01 10 3e 27 9c 45 4f 0a 01
0020   cb f0 00 00 ff cd 00 0d 00 25 00 00 00 00 00 00
0030   00 00 00 00 00 00 00 00 00 00 00 00

image

这是不是go的一个bug??

@alpha-baby
Copy link
Author

在mac 平台上 执行可能需要 sudo

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant