TCP is the transmission control protocol, TCP protocol in IP protocol on the basis of the increase of packet integrity check to ensure the integrity of transmission mechanism, so that it has been widely used in the field of data

Follow these steps to quickly understand the information contained in TCP packets

Description of TCP RFC documents

Reference: RFC tools.ietf.org/html/rfc793

The core TCP packet structure is as follows

The common fields are as follows

field role
Source Port Port number of the packet sending machine
Destination Port Port number of the packet receiving machine
Sequence Number Package number,
Acknowledgment Number Confirm the package,
urg/ack/psh/rst/syn/fin Flag bit that sets the yes/no operation flag
Window Flow control window
Checksum Packet integrity check

The client uses this value to determine whether TCP packets have been altered or tampered with in transit

Get case packets

To obtain a TCP packet using wireshark, right-click on the TCP layer, select Copy, and select as a Hex Stream

The TCP packet data obtained here is as follows

1f90f04f3747d146dcae23f3801831bf14ef00000101080a3176450b31764503
Copy the code

Now you can write a program to parse out the specific data of the message from this TCP hexadecimal

Parse TCP data packets

The conversion relationship between binary digits and hexadecimal digits: One hexadecimal number can represent four binary numbers. For example, binary: 00011111 10010000 can be expressed in hexadecimal: 1F90

You can convert hexadecimal to binary strings using the following code

func hex2bin(hex string) string {
	var bin string

	for i := 0; i < len(hex); i++ {
		hex2int, _ := strconv.ParseInt(string(hex[i]), 16.64)
		bin = bin + fmt.Sprintf("%04b", hex2int)
	}

	return bin
}
Copy the code

Then the TCP datagram information can be read by binary bits, the reference code is as follows

func main(a) {
	atcp := "1f90f04f3747d146dcae23f3801831bf14ef00000101080a3176450b31764503"
	bintcp := hex2bin(atcp)

	sourcePort, _  := strconv.ParseInt(bintcp[0:16].2.64)
	fmt.Printf("sourcePort is %d \n", sourcePort)

	destinationPort, _  := strconv.ParseInt(bintcp[16:32].2.64)
	fmt.Printf("destinationPort is %d \n", destinationPort)

	sequenceNumber, _  := strconv.ParseInt(bintcp[32:64].2.64)
	fmt.Printf("sequenceNumber is %d \n", sequenceNumber)

	acknowledgmentNumber, _  := strconv.ParseInt(bintcp[64:96].2.64)
	fmt.Printf("acknowledgmentNumber is %d \n", acknowledgmentNumber)

	dataOffset, _  := strconv.ParseInt(bintcp[96:100].2.64)
	fmt.Printf("dataOffset is %d \n", dataOffset)

	reserved, _  := strconv.ParseInt(bintcp[100:106].2.64)
	fmt.Printf("reserved is %d \n", reserved)

	// Control Bits Control Bits. The value ranges from 106 to 1012. There are six Bits in total
	urg, _ := strconv.ParseInt(bintcp[106:107].2.64)
	ack, _ := strconv.ParseInt(bintcp[107:108].2.64)
	psh, _ := strconv.ParseInt(bintcp[108:109].2.64)
	rst, _ := strconv.ParseInt(bintcp[109:110].2.64)
	syn, _ := strconv.ParseInt(bintcp[110:111].2.64)
	fin, _ := strconv.ParseInt(bintcp[111:112].2.64)
	fmt.Printf("Control bit identifier as follows :\n")
	fmt.Printf(" urg: %d\n", urg)
	fmt.Printf(" ack: %d\n", ack)
	fmt.Printf(" psh: %d\n", psh)
	fmt.Printf(" rst: %d\n", rst)
	fmt.Printf(" syn: %d\n", syn)
	fmt.Printf(" fin: %d\n", fin)

	// Data window 16 bits
	window, _  := strconv.ParseInt(bintcp[112:128].2.64)
	fmt.Printf("window is %d \n", window)

	/ / checksum 16
	checksum, _  := strconv.ParseInt(bintcp[128:144].2.64)
	fmt.Printf("checksum is %d \n", checksum)

	// urgentPointer
	urgentPointer, _ := strconv.ParseInt(bintcp[144:160].2.64)
	fmt.Printf("urgentPointer is %d \n", urgentPointer)

	// options and padding
	optionsAndPaddings := bintcp[160:]
	fmt.Printf("optionsAndPaddings is %s \n", optionsAndPaddings)

	fmt.Printf("tcp raw data is %s \n", atcp)
	fmt.Printf("tcp bin data is %s \n", bintcp)
	fmt.Printf("tcp bin data length is %d\n".len(bintcp))
}
Copy the code

The execution effect is as follows

The wireshark results are as follows

You can see that parsing is OK

A couple of points to note

The TCP packet data copied in the Wireshark is in hexadecimal format. However, some TCP fields occupy only one bit, and the hexadecimal format is a multiple of 4 in hexadecimal format. Parsing the hexadecimal format directly results in some TCP fields cannot be obtained

TCP packet data is eventually aligned to 32 bits, and the entire TCP packet size is padded to a 32 bit multiple with 0 at the end if it is not exactly a 32 bit multiple

TCP protocol in rfc3168 CWR and ece mark has been added, you can refer to: tools.ietf.org/html/rfc316…

Tcpdump: tcpdump -n -xx -i lo0 -s0 ‘TCP port 8080’

The resources

  1. Github.com/google/pack…
  2. Klamath.stanford.edu/~nickm/pape…
  3. Pcapplusplus. Making. IO/docs/tutori…
  4. Tools.ietf.org/html/rfc793…
  5. Forums.ni.com/t5/LabVIEW/…