nmap / npcap

Nmap Project's Windows packet capture and transmission library
https://npcap.com
Other
2.97k stars 514 forks source link

Checksum on Loopback adapter #715

Open gvanem opened 7 months ago

gvanem commented 7 months ago

I installed NPcap 1.79 some days ago. And it works fine. Thanks! Except that I noted in tcpdump.exe (or windump.exe) all the received IP (?) packets are printed with a cksum 0:

WINDUMP.EXE: listening on \Device\NPF_Loopback, link-type NULL (BSD loopback), snapshot length 262144 bytes
IP (tos 0x0, ttl 128, id 58580, offset 0, flags [none], proto ICMP (1), length 60, bad cksum 0 (->57ea)!)
    127.0.0.1 > 127.0.0.1: ICMP echo request, id 1, seq 36, length 40
IP (tos 0x0, ttl 128, id 58581, offset 0, flags [none], proto ICMP (1), length 60, bad cksum 0 (->57e9)!)
    127.0.0.1 > 127.0.0.1: ICMP echo reply, id 1, seq 36, length 40
IP (tos 0x0, ttl 128, id 58582, offset 0, flags [none], proto ICMP (1), length 60, bad cksum 0 (->57e8)!)
    127.0.0.1 > 127.0.0.1: ICMP echo request, id 1, seq 37, length 40
...

I'm not sure if this is a feature or short-coming of NPcap or not. Or windump? I cannot imagine. I have not enabled checksum offload of my physical networks adapters (if that would make a difference. I think not).

I also see these cksum 0 for loopback traffic inside the Thunderbird email client (when I press About | Check for updates etc.).

To Reproduce

In a Windows-shell (like CMD, yuk!):

start c:\Windows\system32\ping.exe -n 1000 -4 127.0.0.1
windump.exe -vtn -i \Device\NPF_Loopback

and notice all the cksum 0 texts. Seems only the IP-checksums are 0 and the TCP/UDP check-sums are OK.

Expected behavior

I want checksum to appear as they are sent by ping.exe, Thunderbird or whatever.

Screenshots

A start windump.exe --color -vvtni \Device\NPF_Loopback followed by a ping -n 3 -4 127.0.0.1 look like:

npcap-loopback

guyharris commented 7 months ago

I think Windows is a bit different from most if not all UN*Xes, i that it loops back traffic (probably both explicitly to 127.0.0.1 and traffic sent to an IP address assigned to one of the machine's own interfaces) without sending it through a "loopback adapter".

At least on macOS:

$ ifconfig lo0
lo0: flags=8049<UP,LOOPBACK,RUNNING,MULTICAST> mtu 16384
    options=1203<RXCSUM,TXCSUM,TXSTATUS,SW_TIMESTAMP>
    inet 127.0.0.1 netmask 0xff000000 
    inet6 ::1 prefixlen 128 
    inet6 fe80::1%lo0 prefixlen 64 scopeid 0x1 
    nd6 options=201<PERFORMNUD,DAD>

so the loopback interface has both

#define IFCAP_RXCSUM            0x00001 /* can offload checksum on RX */
#define IFCAP_TXCSUM            0x00002 /* can offload checksum on TX */

supported - which doesn't really mean that the checksum is offloaded, as there's no NIC to which to offload it, it just means "if memory and the networking stack can't be trusted not to corrupt the packet, we have bigger problems, so don't bother with checksumming loopback traffic".

And, if I run tcpdump -v -i lo0 and ping 127.0.0.1 in parallel, I do, in fact, get

10:56:36.704203 IP (tos 0x0, ttl 64, id 45714, offset 0, flags [none], proto ICMP (1), length 84, bad cksum 0 (->ca14)!)
    localhost > localhost: ICMP echo request, id 25009, seq 8, length 64
10:56:36.704252 IP (tos 0x0, ttl 64, id 18475, offset 0, flags [none], proto ICMP (1), length 84, bad cksum 0 (->347c)!)
    localhost > localhost: ICMP echo reply, id 25009, seq 8, length 64
10:56:37.704843 IP (tos 0x0, ttl 64, id 28446, offset 0, flags [none], proto ICMP (1), length 84, bad cksum 0 (->d89)!)
    localhost > localhost: ICMP echo request, id 25009, seq 9, length 64
10:56:37.704869 IP (tos 0x0, ttl 64, id 7596, offset 0, flags [none], proto ICMP (1), length 84, bad cksum 0 (->5efb)!)
    localhost > localhost: ICMP echo reply, id 25009, seq 9, length 64
10:56:38.708813 IP (tos 0x0, ttl 64, id 20941, offset 0, flags [none], proto ICMP (1), length 84, bad cksum 0 (->2ada)!)
    localhost > localhost: ICMP echo request, id 25009, seq 10, length 64
10:56:38.708858 IP (tos 0x0, ttl 64, id 39189, offset 0, flags [none], proto ICMP (1), length 84, bad cksum 0 (->e391)!)
    localhost > localhost: ICMP echo reply, id 25009, seq 10, length 64

so the same thing is happening there. I suspect the same would happen on Linux/*BSD/Solaris/AIX/etc.

Windows, not having a loopback device in its networking stack, may not have a way to indicate through "query network adapter" calls, but I suspect the same thing is happening here.

Npcap's loopback adapter, as I understand it, is a special hack to allow that traffic to be captured, so you can't query its checksum-offloading using ipconfig. However, if libpcap were to be enhanced to provide a way to get checksum offloading feature information, Npcap could either try to find out what Windows is doing for loopback traffic, if there's a way to do that, or could just say "yup, loopback traffic gets IP checksums offloaded". (I don't know why it doesn't offload TCP/UDP checksums; perhaps neither TCP nor UDP knows that the packets will go over the loopback code path.)

If loopback were enhanced in that fashion, tcpdump could avoid checking the checksums if they're marked as offloaded and, if libpcap is also enhanced to read and write pcapng files, and pcapng were to provide checksum offloading indications either in IDBs or EPBs, tcpdump (and Wireshark/TShark) could also avoid checking it in pcapng capture files.

gvanem commented 7 months ago

If loopback were enhanced in that fashion, tcpdump could avoid checking the checksums if they're marked as offloaded ...

That would be nice to avoid all this noise. Check for something like:

if ((pcap_dev->flags & PCAP_IF_LOOPBACK) && 
   !(pcap_dev->flag & PCAP_IF_LOOPBACK_NO_CHECKSUM))
  // do not print 'cksum 0'
  ...

But where could libpcap get this info from? IpHlpAPI is of no real help here.

guyharris commented 7 months ago

!(pcap_dev->flag & PCAP_IF_LOOPBACK_NO_CHECKSUM))

That should be done for all adapters, at least for transmitted packets, not just the loopback adapter.

But where could libpcap get this info from? IpHlpAPI is of no real help here.

If we go wandering in the Land of OID, we find OID_TCP_OFFLOAD_CURRENT_CONFIG, which seems to provide a whole bunch of "what sort of offloading is being done" information; the Npcap driver provides an ioctlDeviceIoControl() to get and set OIDs, with its Packet32 library providing PacketRequest() to do that, and libpcap on Windows providing oid_get_request()/oid_set_request(), so libpcap could use that.

I'm not sure whether the NDIS OID get/set calls would work on the loopback device, but, if not, at one of those three layers - driver, Packet32 or libpcap - the loopback device could be handled specially.

gvanem commented 7 months ago

Many years ago I made a change for windump -Dvv to be extra verbose:

 7. \Device\NPF_{6568F487-0016-453C-8C29-5C28DEDF27A0} [Up, Running, Connected]
   Description:     Realtek PCIe GbE Family Controller
   Unicast Addr:    fe80::a087:37e9:a635:f23c, 10.0.0.10
   Anycast Addr:    <None>
   Multicast Addr:  ff01::1, ff02::1, ff02::c, ff02::fb, ff02::1:3, ff02::1:ff00:4f34, ff02::1:ff06:7ac, ff02::1:ff35:f23c, ff02::1:ff37:1585, ff02::1:ff41:5ffc
   DNS Servers:     193.213.112.4, 8.8.8.8
   IfType:          Ethernet (6)
   OperStatus:      Up (1)
   MAC address:     D8:BB:C1:06:16:48 (AMD-PC, Micro-Star INTL CO., LTD.)
   MTU:             1480
   Tx speed:        1 GB/s
   Rx speed:        1 GB/s
   WINS servers:    <None>
   Gateways:        <None>
   IPv4 metric:     25
   IPv6 metric:     25
   Adapter Flags:   NDIS
   Phys media:      Unspecified
   Link state:      <failed>
   NDIS ver:        6.40
   Drvr version:    10.54.1111.2021
   Drvr date:       11-11-2021
   Drvr installed:  10-06-2023, 09:42:19
   Dev. instance:   PCI\VEN_10EC&DEV_8168&SUBSYS_7C911462&REV_15\6&10d9d0ba&0&0038020A
   PnPCapabilities: 0x0100
   ServiceName:     rt640x64
   Available OIDs for this adapter:
     0x00010101 OID_GEN_SUPPORTED_LIST
     ...
    160 OIDs (2 unknown, 40 duplicates).

 8. \Device\NPF_Loopback [Up, Running, Loopback]
   Description:     Adapter for loopback traffic capture
   Adapter Flags:   <N/A>
   Phys media:      <N/A>
   Link state:      <N/A>
   NDIS ver:        <N/A>
   Available OIDs for this adapter:
     <None>

My code is simply calling:

  struct {
    PACKET_OID_DATA oidData;
    DWORD           values [1000];
  } oid;
  BOOL rc;
  memset (&oid, 0, sizeof(oid));
  oid.oidData.Oid = OID_GEN_SUPPORTED_LIST;
  oid.oidData.Length = sizeof(oid);

  if (air_hnd)
       rc = (DeviceIoControl(air_hnd, oid.oidData.Oid, NULL, 0, NULL, 0, &oid.oidData.Length, NULL) == TRUE);
  else rc = (PacketRequest(adapter, FALSE, &oid.oidData) == TRUE);
  if (rc) {
   // dump all OIDs
  }

Now with NPcap and a PacketRequest(adapter,..); for the Loopback, rc == FALSE. Yikes!

So I guess a Loopback Adapter does not try to resemble a physical adapter at all. But I've never tested my code with such a strange beast (since I installed NPcap 1.79 only last week).

But other pseudo-adapters like WAN Miniport, do indeed look like a physical adapter:

 3. \Device\NPF_{7D3F744A-F0AD-44BD-82C8-B27C74755C6A} [Up, Running, Connected]
   Description:     WAN Miniport (IP)
   Unicast Addr:    <None>
   Anycast Addr:    <None>
   Multicast Addr:  <None>
   DNS Servers:     <None>
   IfType:          Ethernet (6)
   OperStatus:      Up (1)
   MAC address:     <None>
   MTU:             1500
   Tx speed:        0 
   Rx speed:        0 
   WINS servers:    <None>
   Gateways:        <None>
   Adapter Flags:   NDIS
   Phys media:      Unspecified
   Link state:      <failed>
   NDIS ver:        6.30
   Drvr version:    10.0.19041.1
   Drvr date:       6-21-2006
   Drvr installed:  15-07-2022, 21:35:00
   Dev. instance:   SWD\MSRRAS\MS_NDISWANIP
   PnPCapabilities: <Unknown>
   ServiceName:     NdisWan
   Available OIDs for this adapter:
     0x00010101 OID_GEN_SUPPORTED_LIST
   ...
  104 OIDs