the-tcpdump-group / libpcap

the LIBpcap interface to various kernel packet capture mechanism
https://www.tcpdump.org/
Other
2.57k stars 824 forks source link

Capturing injected packets not working on Linux #1208

Open amurzeau opened 11 months ago

amurzeau commented 11 months ago

Hi,

I've found that on Linux, sent packets using pcap_sendpacket or pcap_inject are not captured by pcap_dispatch (using the same pcap instance).

I think I got the same as this older issue: https://github.com/the-tcpdump-group/libpcap/issues/400

I encountered it while testing a Windows application that use Winpcap under wine (which implements winpcap using libpcap).

Is there a way to still enable that ?

As an alternative, opening a different pcap handle works, one handle to send packets and another different handle to receive packet. This way, sent packets are captured by pcap_dispatch. Maybe that's the way to go then ?

Thanks !

infrastation commented 11 months ago

Does this reproduce without Wine?

amurzeau commented 10 months ago

Hi,

Sorry the delay. I've tested on Linux without Wine and I reproduce the behavior. pcap_dispatch does not receive packets sent by pcap_inject on the same pcap_t handle.

But when using a different handle for pcap_dispatch and pcap_inject, pcap_dispatch receive injected packets.

See bellow for a test application ```c // This is an example program from the website www.microhowto.info // © 2012 Graham Shaw // Copying and distribution of this software, with or without modification, // is permitted in any medium without royalty. // This software is offered as-is, without any warranty. // Purpose: to construct an ARP request and write it to an Ethernet interface // using libpcap. // // See: "Send an arbitrary Ethernet frame using libpcap" // http://www.microhowto.info/howto/send_an_arbitrary_ethernet_frame_using_libpcap.html // Compile with gcc send_arp.c -o send_arp -lpcap // Uncomment this to test pcap_inject using the same libpcap instance as pcap_dispatch #define TEST_SINGLE_PCAP_INSTANCE #include #include #include #include #include #include #include #include #include #include struct frame_t { struct ether_header eth_header; }; struct ether_header frame; pcap_t* pcap; pcap_t* pcap2; void handler(u_char *user, const struct pcap_pkthdr *header, const u_char *data) { // Write the Ethernet frame to the interface. const struct ether_header *data_eth = (struct ether_header*) data; pcap_inject(pcap2,&frame,sizeof(frame)); printf("received packet with size: %d, ether_type: 0x%x\n", header->caplen, data_eth->ether_type); } int main(int argc,const char* argv[]) { // Get interface name and target IP address from command line. if (argc<2) { fprintf(stderr,"Usage: send_arp \nExample: send_arp eth0\n"); exit(1); } const char* if_name=argv[1]; const unsigned char source_mac_addr[]={0x02, 0x02, 0x02, 0x02, 0x02, 0x02}; const unsigned char destination_mac_addr[]={0x02, 0x02, 0x02, 0x02, 0x02, 0x02}; memcpy(frame.ether_shost,source_mac_addr,sizeof(frame.ether_shost)); memcpy(frame.ether_dhost,destination_mac_addr,sizeof(frame.ether_dhost)); frame.ether_type = 0x1234; // Open a PCAP packet capture descriptor for the specified interface. char pcap_errbuf[PCAP_ERRBUF_SIZE]; pcap_errbuf[0]='\0'; pcap=pcap_open_live(if_name,1514,1,1,pcap_errbuf); #ifndef TEST_SINGLE_PCAP_INSTANCE // If not testing single pcap instance, use a second instance for the pcap_inject call pcap2=pcap_open_live(if_name,1514,1,1,pcap_errbuf); #else pcap2 = pcap; #endif if (pcap_errbuf[0]!='\0') { fprintf(stderr,"%s\n",pcap_errbuf); } if (!pcap) { exit(1); } // Write the Ethernet frame to the interface. if (pcap_inject(pcap2,&frame,sizeof(frame))==-1) { pcap_perror(pcap,0); pcap_close(pcap); exit(1); } while(1) pcap_dispatch(pcap, -1, handler, NULL); if (pcap_errbuf[0]!='\0') { fprintf(stderr,"%s\n",pcap_errbuf); } // Close the PCAP descriptor. pcap_close(pcap); return 0; } ```