Note that there are some explanatory texts on larger screens.

plurals
  1. POMac changes IP total length field
    primarykey
    data
    text
    <p>I'm programming with sockets in Mac 10.6.8. Whenever I receive a packet, it starts with the IP header. I've been using Wireshark to analyze incoming packets, and I noticed that my machine's socket implementation will consistently change the "total length" field in the IP header. Specifically, it will subtract the IP header length and reverse the bytes (from network to host order).</p> <p>For example, here's the beginning of an IP header as reported by Wireshark:</p> <pre><code>45 c0 00 38 ... </code></pre> <p>That breaks down as follows:</p> <ul> <li>4 bits (0x4): IP version: 4</li> <li>4 bits (0x5): IP header length: 5 words (20 bytes)</li> <li>8 bits (0xc0): differentiated services flags</li> <li>16 bits (0x0038): total length: 56 bytes</li> </ul> <p>However, when I print the contents of the buffer filled by <code>recvfrom</code> for the same packet, I get a different lede:</p> <pre><code>ssize_t recvbytes = recvfrom(sock-&gt;fd, buffer, size, /*flags=*/0, (struct sockaddr*)src, &amp;src_len); </code></pre> <p>returns</p> <pre><code>45 c0 24 00 ... </code></pre> <ul> <li>4 bits (0x4): IP version: 4</li> <li>4 bits (0x5): IP header length: 5 words (20 bytes)</li> <li>8 bits (0xc0): differentiated services flags</li> <li>16 bits (0x2400): total length: 9216 bytes (?!)</li> </ul> <p>I figured out that before I get access to the buffer, the socket implementation is reading the total length, subtracting the IP header length, and then writing it back in host order (little endian on my machine) rather than network order (big endian). In this example, that means:</p> <ul> <li>read the total length: 0x0038 = 56</li> <li>subtract the header length: 56 - 20 = 36</li> <li>write back in host order: 36 = 0x0024 (big endian) = 0x2400 (little endian = host order on my machine)</li> </ul> <p>The problem gets worse. It won't just change the total length of the outermost IP header. It will also change the total length fields of internal IP headers, e.g., the one buried in an ICMP "time exceeded" message (which must include the original IP header of the dropped packet). Funnier still, it won't subtract the IP header length from the internal headers; it just reverses the byte order.</p> <p>Is this happening to anyone else? Is it part of a standard I'm unaware of? Is there a way to fix my machine's socket implementation to stop tampering with packets? How is Wireshark able to get around this problem?</p> <p>Thanks in advance for your consideration.</p> <p>EDIT: My code and Makefile are available <a href="https://github.com/thejohnfreeman/netutils" rel="nofollow">on GitHub</a>. I wrote a <code>fixip_osx</code> function to allow verifying IP checksums:</p> <p><a href="https://github.com/thejohnfreeman/netutils/blob/master/lib/ip.c" rel="nofollow">https://github.com/thejohnfreeman/netutils/blob/master/lib/ip.c</a></p> <pre><code>void fixip_osx(struct ip* ip) { /* Something on my Mac subtracts the header length from `ip_len` and stores * it in host order (little endian). */ u16_t ip_hdrlen = ip-&gt;ip_hl &lt;&lt; 2; u16_t ip_totlen = ip-&gt;ip_len + ip_hdrlen; ip-&gt;ip_len = htons(ip_totlen); } </code></pre> <p>However, it's still a problem for verifying ICMP checksums when the payload contains another IP header.</p> <p>The problem exists whether I compile with Clang 3.2 (built from trunk) or GCC 4.7 (MacPorts port), so I assume the problem lies in either the sockets implementation (packaged with Mac OS) or in Mac OS X itself.</p>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload