The purpose of this paper is to intercept a segment of network packets randomly and then parse out this segment of memory according to the protocol type.

To learn the basics of this article:

  1. Network protocol
  2. The C language
  3. Linux operating
  4. Use the packet capture tool

For the installation and use of the packet capture tool, see the following:

“A packet you learn to network data packet”

The video teaching links are as follows:

How to Grab packets from a Network

Intercept a network packet

Use the packet capture tool to capture a RANDOM TCP packet

The data packet information parsed by the Collet packet capture tool is as follows:Packet memory information:Data information can be copied directly:

Two, the structure used

Below, you will learn how to parse these data packets.

We can find the definition of the protocol header in the Linux kernel

  • The etheric head:
drivers\staging\rtl8188eu\include\if_ether.h	
Copy the code
struct ethhdr {
	unsigned char	h_dest[ETH_ALEN];	/* destination eth addr	*/
	unsigned char	h_source[ETH_ALEN];	/* source ether addr	*/
	unsigned short	h_proto;		/* packet type ID field	*/
};
Copy the code
  • The IP header
	include\uapi\linux\ip.h	
Copy the code
struct iphdr {
#if defined(__LITTLE_ENDIAN_BITFIELD)  // Little endian mode
	__u8	ihl:4,
		version:4;
#elif defined(__BIG_ENDIAN_BITFIELD)    // Big endian mode
	__u8	version:4,
		ihl:4;
#endif
	__u8	tos;
	__u16	tot_len;
	__u16	id;
	__u16	frag_off;
	__u8	ttl;
	__u8	protocol;
	__u16	check;
	__u32	saddr;
	__u32	daddr;
	/*The options start here. */
};
Copy the code

The TCP header

include\uapi\linux\tcp.h
Copy the code
struct tcphdr {
	__be16	source;
	__be16	dest;
	__be32	seq;
	__be32	ack_seq;
#if defined(__LITTLE_ENDIAN_BITFIELD)
	__u16	res1:4,
		doff:4,
		fin:1,
		syn:1,
		rst:1,
		psh:1,
		ack:1,
		urg:1,
		ece:1,
		cwr:1;
#elif defined(__BIG_ENDIAN_BITFIELD)
	__u16	doff:4,
		res1:4,
		cwr:1,
		ece:1,
		urg:1,
		ack:1,
		psh:1,
		rst:1,
		syn:1,
		fin:1;
#else
#error	"Adjust your <asm/byteorder.h> defines"
#endif	
	__be16	window;
	__sum16	check;
	__be16	urg_ptr;
};
Copy the code

Because the length of the header is defined according to the standard protocol,

So the Ethernet is 14, the IP header is 20, the TCP header is 20,

The memory space of each protocol header is as follows:

Three, resolve the Ethernet head

#define MAC_ARG(p) p[0],p[1],p[2],p[3],p[4],p[5]
Copy the code
	struct ethhdr *ethh;
	unsigned char *p = pkt;
	
	ethh = (struct ethhdr *)p;

	printf("h_dest:%02x:%02x:%02x:%02x:%02x:%02x \n", MAC_ARG(ethh->h_dest));
	printf("h_source:%02x:%02x:%02x:%02x:%02x:%02x \n", MAC_ARG(ethh->h_source));
	printf("h_proto:%04x\n",ntohs(ethh->h_proto));
Copy the code

Ethh ->h_proto is short, which is 2 bytes, so you need to use the ntohs function to store the data locally: n: network byte order h: host byte order s: Short 2 bytes L: long 4 bytes nTOHL () : 4 bytes Converts the network byte order data into the host byte order HTons () : 2 bytes Converts the host byte order data into the network byte order nTOhs () : 2 bytes Converts the network byte order data into the host byte order htonL () : 4 bytes Host byte order Data is converted to network byte order

When the following statement is executed,

ethh = (struct ethhdr *)p;
Copy the code

The member mappings of the structure pointer variable ETH are as follows:

The final print result is as follows:

Parse the IP header

Resolving IP headers is simple.

To find the IP header, start from the PKT header and offset the Ethernet header length (14 bytes).

The parse code looks like this:

#define IP_ARG(p)  p[0],p[1],p[2],p[3]
Copy the code
	/* Parse the IP header */
	if(ntohs(ethh->h_proto) == 0x0800)
	{
	
		iph = (struct iphdr *)(p + sizeof(struct ethhdr));

		q = (unsigned char *)&(iph->saddr);
		printf("src ip:%d.%d.%d.%d\n",IP_ARG(q));

		q = (unsigned char *)&(iph->daddr);
		printf("dest ip:%d.%d.%d.%d\n",IP_ARG(q));
	}
Copy the code

The final analysis result is as follows:

As you can see, we have resolved the IP address correctly, and the results are consistent with the data analyzed by the packet capture tool.

The protocol field indicates the protocol type following the IP protocol. Common values are as follows:

The numerical describe
0 Reserved field for IPv6(jump-to-jump option)
1 Internet Control Message (ICMP)
2 Internet Group Management (IGMP)
3 Gateway to gateway (GGP)
4 IP in 1P (encapsulation)
6 Transmission Control (TCP)
7 CBT
8 External Gateway Protocol (EGP)
9 Any private internal gateway (Cisco uses in its IGRP implementation) (IGP)
10 BBNRCC monitoring
11 Voice over Network Protocol
12 PUP
13 ARGUS
14 EMCON
15 Network diagnostic tool
16 Chaos (Chaos)
17 User Data Packet (UDP)
41 1Pv6
58 1 pv6 ICMP
59 1Pv6 has no next header
60 IPv6 messenger options
89 OSPF IGP
92 Multicast Transport protocol
94 IP internal IP encapsulation protocol
95 Mobile Network interconnection Control Protocol
96 Flag communication security protocol
97 Ethernet encapsulation in IP
98 Encapsulated header
100 GMTP
101 Ipsilon Traffic management protocol
133 ~ 254 undistributed
255 keep

Parse the TCP header

Looking up the TCP header is a good idea,

To find the TCP header, start with the PKT header and offset the Ethernet header length (14 bytes) and IP header length (20 bytes).

	switch(iph->protocol)
		{
			case 0x1:
				//icmp
				break;
			case 0x6:
				//tcp				
				tcph = (struct tcphdr *)(p + sizeof(struct ethhdr) + sizeof(struct iphdr));
				printf("source:%d dest:%d \n",ntohs(tcph->source),ntohs(tcph->dest);	

				break;
			case 0x11:
				//udp
				
				break;
		}
Copy the code

Structure and memory mapping

The print result is as follows:

Learn to print this memory in different formats

In a real project, we might not be parsing standard TCP/IP protocol packets,

It could be our own defined protocol packet,

Once you’ve mastered the above techniques,

All protocol analysis can be done easily!

Sometimes we need to print out the data frames sent by the other party,

Often we print everything out in hexadecimal format,

This is the best way to analyze the content of the data.

1. Print by byte

The code is as follows:

	for(i=0; i<400; i++) {printf("%02x ",pkt[i]);
		if(i%20= =19)
		{
			printf("\n"); }}Copy the code

2. Analyze a memory segment by short

When we receive data, we use an unsigned char array,

But sometimes the data they’re sending might be a two-byte array,

So all we have to do is take a pointer of short to the head of memory,

You can then access the data sent by the other party through that pointer,

It’s important to pay attention to the byte order,

It can vary from scenario to scenario, so be sure to look at it on a case-by-case basis,

In this example, since the network byte order data is converted to host byte order,

So you need to convert the byte order.

// Change the byte order of short
void indian_reverse(unsigned short arr[],int num)
{
	int i;
	unsigned short temp;

	for(i=0; i<num; i++) { temp =0;

		temp = (arr[i]&0xff00) > >8;
		temp |= (arr[i]&0xff) < <8;
		arr[i] = temp;
	}
}
main()
{
	unsigned short spkt[200]; ...........................memcpy(spkt,pkt,sizeof(pkt));

	indian_reverse(spkt,ARRAY_SIZE(spkt));
	
	for(i=0; i<200; i++) {printf("%04x ",spkt[i]);
		if(i%10= =9)
		{
			printf("\n"); }}........................... }Copy the code

Here are the results:Complete code please pay attention to the public number: a mouthful of Linux, reply:Packet parsing