seladb / PcapPlusPlus

PcapPlusPlus is a multiplatform C++ library for capturing, parsing and crafting of network packets. It is designed to be efficient, powerful and easy to use. It provides C++ wrappers for the most popular packet processing engines such as libpcap, Npcap, WinPcap, DPDK, AF_XDP and PF_RING.
https://pcapplusplus.github.io/
The Unlicense
2.74k stars 672 forks source link

Send crafted packet through Device doesn't work #177

Closed laochonlam closed 5 years ago

laochonlam commented 5 years ago

Hi,

I want to craft my own packet and use specific network interface to send that packet immediately.

Then I just follow the tutorial in the section "Packet creation" and modified the code at PcapPlusPlus/Examples/Tutorials/Tutorial-PacketCraftAndEdit/


/* This part is from the example */
    pcpp::EthLayer newEthernetLayer(pcpp::MacAddress("00:50:43:11:22:33"), pcpp::MacAddress("aa:bb:cc:dd:ee"));

    // create a new IPv4 layer
    pcpp::IPv4Layer newIPLayer(pcpp::IPv4Address(std::string("192.168.1.1")), pcpp::IPv4Address(std::string("10.0.0.1")));
    newIPLayer.getIPv4Header()->ipId = htons(2000);
    newIPLayer.getIPv4Header()->timeToLive = 64;

    // create a new UDP layer
    pcpp::UdpLayer newUdpLayer(12345, 53);

    // create a new DNS layer
    pcpp::DnsLayer newDnsLayer;
    newDnsLayer.addQuery("www.ebay.com", pcpp::DNS_TYPE_A, pcpp::DNS_CLASS_IN);

    // create a packet with initial capacity of 100 bytes (will grow automatically if needed)
    pcpp::Packet newPacket(100);

    // add all the layers we created
    newPacket.addLayer(&newEthernetLayer);
    newPacket.addLayer(&newIPLayer);
    newPacket.addLayer(&newUdpLayer);
    newPacket.addLayer(&newDnsLayer);

    // compute all calculated fields
    newPacket.computeCalculateFields();
/* This part is from the example */

        // [1] send immediately
        pcpp::PcapLiveDeviceList::getInstance().getPcapLiveDeviceByName("enp0s31f6");
        if (!dev->open()) 
            std::cout << "device open failed" << std::endl;
    int sentCount = dev->sendPacket(&newPacket);
    std::cout << sentCount << std::endl;

    // [2] while write into "1_new_packet.pcap"
    pcpp::PcapFileWriterDevice writer2("1_new_packet.pcap");
    writer2.open();
    writer2.writePacket(*(newPacket.getRawPacket()));
    writer2.close();

But then I use Wireshark to capture the [1] real-time packet, It seems broken. 1 compared with the [2] packet through PcapFileWriterDevice to "1_new_packet.pcap" 2

I compared the hex of real-time packet and the packet from "1_new_packet.pcap", I found different hex.

//real time packet
0000   00 04 00 01 00 06 00 50 43 11 22 33 00 00 00 03
0010   45 00 00 3a 07 d0 00 00 40 11 a7 39 c0 a8 01 01
0020   0a 00 00 01 30 39 00 35 00 26 d8 5e 00 00 00 00
0030   00 01 00 00 00 00 00 00 03 77 77 77 04 65 62 61
0040   79 03 63 6f 6d 00 00 01 00 01

//through PcapFileWriterDevice to "1_new_packet.pcap"
0000   aa bb cc dd ee 00 00 50 43 11 22 33 08 00 45 00
0010   00 3a 07 d0 00 00 40 11 a7 39 c0 a8 01 01 0a 00
0020   00 01 30 39 00 35 00 26 d8 5e 00 00 00 00 00 01
0030   00 00 00 00 00 00 03 77 77 77 04 65 62 61 79 03
0040   63 6f 6d 00 00 01 00 01

The situation continued when the packet only contains Ethernet layer, so It might be the problem of Ethernet layer.

Instead, I try to craft the same packet by using Scapy, that works (can be recognized in Wireshark). Therefore I wanna know if there are any different implementation between PcapPlusPlus and Scapy, and the reason of this problem.

Any idea? Thanks!

Lam

seladb commented 5 years ago

Thanks for reporting this issue! It seems that the link layer of your NIC is not Ethernet. When Wireshark/libpcap cannot recognize the link layer it assumes SLL link layer, please read more here: https://wiki.wireshark.org/SLL

Can you please find out the link layer and let me know?

laochonlam commented 5 years ago

@seladb Hi, thanks for the reply

the link layer of my NIC is Ethernet, I have tested several NIC cards and run the code in two Ubuntu 16.04 machine, but that's the same situation. Therefore I think that isn't the problem of my NIC card.

I think the situation can be easily reproduced from your machine.

Thanks!

Lam

seladb commented 5 years ago

I'll try to run your code and let you know

seladb commented 5 years ago

hi, I ran the exact same code on Ubuntu 16.04 VirtualBox VM and managed to see the generated packet in Wireshark:

bug177

Could you please print the output of ifconfig in your machine?

seladb commented 5 years ago

Please let me know if there is any way I can reproduce this issue

laochonlam commented 5 years ago

@seladb Sorry for the late reply,

I gonna try this again tomorrow (maybe install the version without DPDK supported, I doubted there are something related) and let you know the further information,

thanks a lot

Lam

laochonlam commented 5 years ago

I figured out how to reproduce it but don't understand the reason why...

Screenshot from 2019-04-30 20-09-41 When I choose "any" interface to capture, the packet become EthernetII when I choose my "enp0s31f6" interface, It parsed the DNS packet right.

btw my ifconfig, Screenshot from 2019-04-30 20-22-27

Thanks!

Lam

seladb commented 5 years ago

Now it is clear :) any interface in Wireshark is not a real interface but rather a Wireshark thing that listens to all the interfaces on the machine. You can read about it here. One of the interfaces may be loopback which is a virtual interface built in Linux that doesn't use Ethernet II but rather SLL - Linux Cooked Capture. That's why you probably see all packets as SLL instead of Ethernet II.

If you're getting the correct packet while listening to the real interface packets are coming to (enp0s31f6 in your case) then I think it's all good.

Please let me know if you have any questions. Otherwise you may close the issue.

laochonlam commented 5 years ago

Thanks for your time! @seladb