libpcap on MacOS
The pcap
library is one of the most famous and used network packet sniffing tool around the world. libpcap is the underlying library running under the famous tcpdump
program which is a powerful network diagnosis tool.
What is pcap
pcap
stands for: Packet Capture. The library which contains the pcap
module, is called libpcap
and Linux-based distros ship with it by default. If you’re on a Mac (like me), installing this library is easy-peasy thanks to the amazing (and almighty) Homebrew.
This library is the powerful back end for the powerful tool tcpdump
so you can really get an idea of how powerful it is. The library is designed to work on C and C++, and there are ports for Java, Python and other languages.
How to install pcap
To install pcap, we need to have Homebrew installed in our system, you can check if you have Homebrew by running:
$ brew --version
Which should show you something like:
1 2 3 | Homebrew 2.0.0 Homebrew/homebrew-core (git revision a968a; last commit 2019-02-05) Homebrew/homebrew-cask (git revision f3d7c; last commit 2019-02-05) |
In case you do not have installed Homebrew yet, go to Homebrew’s homepage and follow the instructions.
If you got brew, then the next step is simple as in:
$ brew install libpcap
After that, you should be able to use pcap
in your C/C++ programs. Hooray!
Linker and Includes
In order to get the library into your code, you need to specify the object files and the directories from which the compiler will grab the headers. Usually, this means knowing the exact location of your library and probably check out for version upgrades and changes.
If you followed my previous instructions, pcap
will come with a special utility in which the library itself takes care of the paths and object files used in the compilation process.
This utility is as simple as specifying the -lpcap
parameter with your compiler options, easy and simple. When you specify -lpcap
your compiler will use your local $PATH
to get the library and definitions paths and will setup them accordingly. Now, let’s write a sample program to check everything is working ok.
Sample program in C
This is a sample program in C which does 2 basic things:
- Displays a list of all the NICs in your computer and allows you to select one to perform the packet capturing.
- Captures 15 network packets and displays them with the Source MAC, Destiny MAC and the Packet Type.
Source code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 | # ifdef _MSC_VER /* * we do not want the warnings about the old deprecated and unsecure CRT functions * since these examples can be compiled under *nix as well */ # define _CRT_SECURE_NO_WARNINGS # endif # include <pcap.h> /*prototype of the packet handler*/ void packet_handler(u_char *param, const struct pcap_pkthdr*header, const u_char *pkt_data); int main() { pcap_if_t *alldevs; pcap_if_t*d; int inum; int i=0; pcap_t *adhandle; char errbuf[PCAP_ERRBUF_SIZE]; /*Retrieve the device list*/ if(pcap_findalldevs(&alldevs, errbuf) == -1) { fprintf(stderr,"Error in pcap_findalldevs: %s\n", errbuf); exit(1); } /*Print the list*/ for(d=alldevs; d; d=d->next) { printf("%d. %s", ++i, d->name); if (d->description) printf(" (%s)\n", d->description); else printf(" (No description available)\n"); } if(i==0) { printf("\nNo interfaces found! Make sure WinPcap is installed.\n"); return -1; } printf("Enter the interface number (1-%d):",i); scanf("%d", &inum); if(inum < 1 || inum > i) { printf("\nInterface number out of range.\n"); /*Free the device list*/ pcap_freealldevs(alldevs); return -1; } /*Jump to the selected adapter*/ for(d=alldevs, i=0; i< inum-1 ;d=d->next, i++); /*Open the device*/ /*Open the adapter*/ if ((adhandle= pcap_open_live( d->name, // name of the device 65536, // portion of the packet to capture. // 65536 grants that the whole packet will be captured on all the MACs. 1, // promiscuous mode (nonzero means promiscuous) 1000, // read timeout errbuf // error buffer )) == NULL) { fprintf(stderr,"\nUnable to open the adapter. %s is not supported by WinPcap\n", d->name); /*Free the device list*/ pcap_freealldevs(alldevs); return -1; } printf("\nlistening on %s...\n", d->description); /*At this point, we don't need any more the device list. Free it*/ pcap_freealldevs(alldevs); /*start the capture*/ pcap_loop(adhandle, 15, packet_handler, NULL); pcap_close(adhandle); return 0; } /*Callback function invoked by libpcap for every incoming packet*/ void packet_handler(u_char *param, const struct pcap_pkthdr*header, const u_char *pkt_data) { struct tm *ltime; char timestr[16]; time_t local_tv_sec; /* * unused parameters */ (void)(param); (void)(pkt_data); /*convert the timestamp to readable format*/ local_tv_sec = header->ts.tv_sec; ltime=localtime(&local_tv_sec); strftime( timestr, sizeof timestr, "%H:%M:%S", ltime); printf("%s,%.6d len:%d\n", timestr, header->ts.tv_usec, header->len); int j=0,k=0; printf("Destiny MAC:\n"); for(j=0;j<6;j++){ printf("%02X:",pkt_data[j]); } printf("\n Source MAC:\n"); for(k=6;k<12;k++){ printf("%02X: ",pkt_data[k]); } printf(" \n\n"); unsigned short tipo = (pkt_data[12]*256)+pkt_data[13]; printf("Type: %d %02X %02X \n",tipo,pkt_data[12],pkt_data[13]); } |
Save your program as AwesomePacketSniffer.c (or any other kinky name), and you should be good to go.
To compile the program you’ll need to run:
$ gcc AwesomePacketSniffer.c -lpcap -o AwesomePacketSniffer.out
Finally, run the program with:
$ ./AwesomePacketSniffer.out
In case the program isn’t able to detect any network interfaces, try running it with sudo
privileges. Note that this is not the intended way to run this kind of programs so you should check your libpcap
permissions and configuration.
The output
The expected output should be something like:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 | 1. en0 (No description available) 2. p2p0 (No description available) 3. awdl0 (No description available) 4. bridge0 (No description available) 5. utun0 (No description available) 6. en1 (No description available) 7. lo0 (No description available) 8. gif0 (No description available) 9. stf0 (No description available) 10. XHC20 (No description available) Enter the interface number (1-10): 1 listening on (en0)... 09:57:38,578314 len:140 Destiny MAC: E0:55:3D:62:77:A0: Source MAC: D4: 61: 9D: 2D: E1: 58: Type: 2048 08 00 09:57:38,578397 len:662 Destiny MAC: E0:55:3D:62:77:A0: Source MAC: D4: 61: 9D: 2D: E1: 58: Type: 2048 08 00 09:57:38,611104 len:66 Destiny MAC: D4:61:9D:2D:E1:58: Source MAC: E0: 55: 3D: 62: 77: A0: Type: 2048 08 00 09:57:38,611414 len:66 Destiny MAC: D4:61:9D:2D:E1:58: Source MAC: E0: 55: 3D: 62: 77: A0: Type: 2048 08 00 09:57:38,632868 len:147 Destiny MAC: D4:61:9D:2D:E1:58: Source MAC: E0: 55: 3D: 62: 77: A0: Type: 2048 08 00 09:57:38,632872 len:830 Destiny MAC: D4:61:9D:2D:E1:58: Source MAC: E0: 55: 3D: 62: 77: A0: Type: 2048 08 00 09:57:38,632971 len:66 Destiny MAC: E0:55:3D:62:77:A0: Source MAC: D4: 61: 9D: 2D: E1: 58: Type: 2048 08 00 09:57:38,632972 len:66 Destiny MAC: E0:55:3D:62:77:A0: Source MAC: D4: 61: 9D: 2D: E1: 58: Type: 2048 08 00 09:57:38,633381 len:112 Destiny MAC: D4:61:9D:2D:E1:58: Source MAC: E0: 55: 3D: 62: 77: A0: Type: 2048 08 00 09:57:38,633423 len:66 Destiny MAC: E0:55:3D:62:77:A0: Source MAC: D4: 61: 9D: 2D: E1: 58: Type: 2048 08 00 09:57:38,635294 len:112 Destiny MAC: E0:55:3D:62:77:A0: Source MAC: D4: 61: 9D: 2D: E1: 58: Type: 2048 08 00 09:57:38,645214 len:347 Destiny MAC: E0:55:3D:62:77:A0: Source MAC: D4: 61: 9D: 2D: E1: 58: Type: 2048 08 00 09:57:38,645274 len:112 Destiny MAC: E0:55:3D:62:77:A0: Source MAC: D4: 61: 9D: 2D: E1: 58: Type: 2048 08 00 09:57:38,645284 len:709 Destiny MAC: E0:55:3D:62:77:A0: Source MAC: D4: 61: 9D: 2D: E1: 58: Type: 2048 08 00 09:57:38,662611 len:129 Destiny MAC: D4:61:9D:2D:E1:58: Source MAC: E0: 55: 3D: 62: 77: A0: Type: 2048 08 00 |
Conclusion
This library allows us to access network packets and the information we can get from them goes beyond this simple tutorial. If you feel like something’s missing, you’d like to discuss this article or got any comments and/or feedback, you can find me on Twitter as @humbertowoody.