Iterpreting the ip identification field in firewall
The IP identification (ID) field is a two-byte field contained within the packet. Its sole purpose in life is allow IP packets to be fragmented: all fragments should contain the same ID as the original packet so that they can be pasted back together again. Most systems use the concept of a monotonically increasing ID: for each packet sent, the field is increased by one.
There is a little twist to this scenario. A little-endian machine (like Intel processors) stores numbers in reverse byte-order than how numbers are represented on the wire. This means that a monotonically increasing integer from a Wintel box will increment the high-order byte first, whereas a Sun SPARC box will increment the low-order byte first. Therefore, lets say that you are being pinged steadily from both a Sun SPARC and a Wintel, you will see the following sort of progression in the IP ID field:
| SPARC | Wintel |
|---|---|
| 0×01FD | 0xFD01 |
| 0×01FE | 0xFE01 |
| 0×01FF | 0xFF01 |
| 0×0200 | 0×0002 |
| 0×0201 | 0×0102 |
The above numbers are shown in hexadecimal, which shows the byte-order problem. However, many firewall logs (stupidly) show these numbers in decimal. If a firewall system assumes the number is big-endian but the incoming packets are little endian, then the progression of the numbers is hidden. For example:
| IP ID | Big-endian | Little-endian |
|---|---|---|
| 01 FD | 509 | 64769 |
| 01 FE | 510 | 65025 |
| 01 FF | 511 | 65281 |
| 02 00 | 512 | 2 |
| 02 01 | 513 | 258 |
This entire issue is complicated by the fact that a firewall running on a platform doesn’t have to base its decimal calculation of the IP ID field on the underlying CPU. What I mean by this is that the C code that interprets the IP ID could be written in two ways;
/* ID field is a 2-byte number at offset 4 within the IP header */
int ipid_cpu = *(unsigned short*)(iphdr+4);
int ipid_be = iphdr[4] * 256 + iphdr[5];
The first example is CPU dependent: x86 CPUs will pull it out as a little-endian number, but SPARC CPUs will pull it out as a big-endian number. The second form is CPU independent: it tells all CPUs to interpret the field as a big-endian number. Note: ntohs(*(unsigned short*)(iphdr+4)) will crash a SPARC CPU and is not a good solution
Therefore, if you are running a Linux-based x86 firewall that interprets the IP ID field as a little-endian number, then a string of packets from a Wintel box will demonstrate a monotonically increasing number. However, a stream from a SPARC box will show skipping numbers. Conversely, if the Linux-based firewall uses the (correct) field parsing method, you’ll see the reverse.

