[packet capturing] handling switching between network byte order and host byte order

Dear community,

I'm currently programming a tool using libpcap.
While capturing the network packets, I discovered, that there are some issues interpretating the received data.
I filtered for tcp port 80, but it showed up port 20480, which meant for me, to swapp the byte ordering and I got my port 80... for example, here is what I outputted for debugging:



Packet: Eth/IP/TCP  Received: Fri Jan 13 21:42:19 2012
 Offset=947153 (total length: 60 bytes)
Destination: 0:24:fe:e8:c9:54  Source: bc:ae:c5:50:65:88 (type 8)
IP from: 64.12.30.5  to: 192.168.178.40  length=10240 bytes (protocol 6)
Port from: 47873  to: 7662 Flags: ACK 
seq 4137535139  ack 269068102  (tcp header is 20 bytes)

Packet: Eth/IP/TCP  Received: Fri Jan 13 21:42:23 2012
 Offset=466031 (total length: 74 bytes)
Destination: 0:24:fe:e8:c9:54  Source: bc:ae:c5:50:65:88 (type 8)
IP from: 192.168.178.1  to: 192.168.178.40  length=15360 bytes (protocol 6)
Port from: 27919  to: 48438 Flags: SYN 
seq 3089162230  ack 0  (tcp header is 40 bytes)

Packet: Eth/IP/TCP  Received: Fri Jan 13 21:42:23 2012
 Offset=466067 (total length: 54 bytes)
Destination: bc:ae:c5:50:65:88  Source: 0:24:fe:e8:c9:54 (type 8)
IP from: 192.168.178.40  to: 192.168.178.1  length=10240 bytes (protocol 6)
Port from: 48438  to: 27919 Flags: ACK RST 
seq 0  ack 3105939446  (tcp header is 20 bytes)


This output is with unswapped data, so printed, what I received.

Now my question is, when the headers are written in network byte order and the data part isn't: how do I have to handle the fields within the tcp/ip structs?

The IPs are correct printed (IP protocol), the ports (tcp) are not. The IP header length (IHL field) is correctly set to 5 (ip), the tcp header (data_offset @ tcp) is also already setted correct (without byte swapping).

Which fields must be byte swapped? The ack, seq fields , too? Are the flags now wrong set?

It looks to me as a mixture of swapped and not swapped data what I do not understand...

Just for you to know how the output has been made:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
my_callback(const struct pcap_pkthdr* hdr,const u_char* packet)
	{
		u_char *ptr;
		const u_char *packet_data;
		struct ether_header *eptr;
		int i;
		const struct ip* ippkt;
		struct in_addr source_ip, destination_ip;
		char ipstr_src[INET_ADDRSTRLEN], ipstr_dst[INET_ADDRSTRLEN];
		const struct tcphdr *tcpheader, *tcphdr2;


		//do some typecastings to access the received data as valid headers
		eptr = (struct ether_header*)(packet);
		ippkt = (struct ip*)(packet + sizeof(struct ether_header));
		tcpheader = (struct tcphdr*)(packet + sizeof(struct ether_header) + (ippkt->ip_hl*4));
		tcphdr2 = (struct tcphdr*)(packet + sizeof(struct ether_header) + sizeof(struct ip));
		packet_data = packet + sizeof(struct ether_header) + (ippkt->ip_hl*4) + (tcpheader->doff*4);

		//obtain ips and convert to string
		source_ip = ippkt->ip_src;
		destination_ip = ippkt->ip_dst;
		inet_ntop(AF_INET, &(source_ip), ipstr_src, INET_ADDRSTRLEN);
		inet_ntop(AF_INET, &(destination_ip), ipstr_dst, INET_ADDRSTRLEN);


		//print ethernet macs
		ptr = eptr->ether_shost;
		i = ETHER_ADDR_LEN;

		printf("Packet: Eth/IP/TCP  Received: %s Offset=%u (total length: %u bytes)\n", ctime((const time_t*)&hdr->ts.tv_sec), hdr->ts.tv_usec, hdr->len);
		printf("Destination:");

		do{
			printf("%s%x",(i == ETHER_ADDR_LEN) ? " " : ":",*ptr++);
		}while(--i>0);
		printf("  Source:");
		ptr = eptr->ether_dhost;
	   i = ETHER_ADDR_LEN;
	   do{
		   printf("%s%x",(i == ETHER_ADDR_LEN) ? " " : ":",*ptr++);
	   }while(--i>0);
		printf(" (type %d)\n", eptr->ether_type);

		//build tcp flags string
		std::stringstream tcp_flags;
	    tcp_flags << (tcpheader->urg==1 ? "URG " : "") << (tcpheader->ack==1 ? "ACK " : "") << (tcpheader->psh==1 ? "PSH " : "") << (tcpheader->rst==1 ? "RST " : "") << (tcpheader->syn==1 ? "SYN " : "") << (tcpheader->fin==1 ? "FIN " : "");


		//print out information
		printf("IP from: %s  to: %s  length=%u bytes (protocol %u)\n", ipstr_src, ipstr_dst, ippkt->ip_len, ippkt->ip_p);
		printf("Port from: %u  to: %u Flags: %s\n", (tcpheader->source), (tcpheader->dest), tcp_flags.str().c_str());
		printf("seq %u  ack %u  (tcp header is %u bytes)\n", (tcpheader->seq), (tcpheader->ack_seq), tcpheader->doff*4);
		printf("\n");
	}


Many thanks for your help :D


Kind Regards,
Sebastian
I figured it mostly out by myself. I used a paralell working instance of tcpdump and logged my programs output to a file.
These two files I compared with wireshark, gedit and this nice tool http://www.binaryconvert.com to see if the byte order was changed from a value or not.

At the end the funcs ntohs, ntohl (does it mean network to host short- long ???) did the job.

I only had to swapp certain fields not all, what was a bit confusing to me, but I explained it myself this way: Bit-Fields don't have to be changed as they will be read equal in little endian as in big endian. also one bytes values are not threaten different.
But using variables of type short int (16 bits) and int (32 bits) there is a need for the bytes to be swapped with the functions described above.

If a forgot something, please add it and explain it so me, it is really useful to me :)
For everyone else having the same problem, have fun with this solution :D

Sebastian
Topic archived. No new replies allowed.