1 // most of this copied from http://www.tcpdump.org/pcap.html and other places
8 /* Ethernet addresses are 6 bytes */
9 #define ETHER_ADDR_LEN 6
11 /* ethernet headers are always exactly 14 bytes */
12 #define SIZE_ETHERNET 14
15 struct sniff_ethernet {
16 u_char ether_dhost[ETHER_ADDR_LEN]; /* Destination host address */
17 u_char ether_shost[ETHER_ADDR_LEN]; /* Source host address */
18 u_short ether_type; /* IP? ARP? RARP? etc */
23 u_char ip_vhl; /* version << 4 | header length >> 2 */
24 u_char ip_tos; /* type of service */
25 u_short ip_len; /* total length */
26 u_short ip_id; /* identification */
27 u_short ip_off; /* fragment offset field */
28 #define IP_RF 0x8000 /* reserved fragment flag */
29 #define IP_DF 0x4000 /* dont fragment flag */
30 #define IP_MF 0x2000 /* more fragments flag */
31 #define IP_OFFMASK 0x1fff /* mask for fragmenting bits */
32 u_char ip_ttl; /* time to live */
33 u_char ip_p; /* protocol */
34 u_short ip_sum; /* checksum */
35 struct in_addr ip_src,ip_dst; /* source and dest address */
37 #define IP_HL(ip) (((ip)->ip_vhl) & 0x0f)
38 #define IP_V(ip) (((ip)->ip_vhl) >> 4)
41 typedef u_int tcp_seq;
44 u_short th_sport; /* source port */
45 u_short th_dport; /* destination port */
46 tcp_seq th_seq; /* sequence number */
47 tcp_seq th_ack; /* acknowledgement number */
48 u_char th_offx2; /* data offset, rsvd */
49 #define TH_OFF(th) (((th)->th_offx2 & 0xf0) >> 4)
59 #define TH_FLAGS (TH_FIN|TH_SYN|TH_RST|TH_ACK|TH_URG|TH_ECE|TH_CWR)
60 u_short th_win; /* window */
61 u_short th_sum; /* checksum */
62 u_short th_urp; /* urgent pointer */
70 unsigned int bytesA, bytesB;
73 struct con *cons = NULL;
79 void packet_handler(u_char *user, const struct pcap_pkthdr *h, const u_char *packet) {
80 unsigned int len = h->len;
82 /* The ethernet header */
83 //const struct sniff_ethernet *ethernet = (struct sniff_ethernet*)(packet);
85 const struct sniff_ip *ip = (struct sniff_ip*)(packet + SIZE_ETHERNET);
86 u_int size_ip = IP_HL(ip)*4;
88 printf(" * Invalid IP header length: %u bytes\n", size_ip);
92 const struct sniff_tcp *tcp = (struct sniff_tcp*)(packet + SIZE_ETHERNET + size_ip);
93 u_int size_tcp = TH_OFF(tcp)*4;
95 printf(" * Invalid TCP header length: %u bytes\n", size_tcp);
99 // construct name string
100 // length of IP: 3+1+3+1+3+1+3=15
102 // total: 2*(15+1+5)+4+1=47 including '\0'
104 uint32_t ipA = ntohl(ip->ip_src.s_addr);
105 uint32_t ipB = ntohl(ip->ip_dst.s_addr);
106 sprintf(name, "%u.%u.%u.%u:%u -> %u.%u.%u.%u:%u",
107 ipA>>24, (ipA>>16)&0xff, (ipA>>8)&0xff, ipA&0xff, ntohs(tcp->th_sport),
108 ipB>>24, (ipB>>16)&0xff, (ipB>>8)&0xff, ipB&0xff, ntohs(tcp->th_dport));
110 //printf("%s: %u\n", name, len);
113 HASH_FIND_STR(cons, name, c);
115 c = calloc(1, sizeof(struct con));
116 if (!c) printf("calloc fail"), exit(1);
117 strcpy(c->name, name);
118 HASH_ADD_STR(cons, name, c);
128 int main(int argc, char **argv) {
129 if (argc != 2) puts("invocation: ./pulserecord <interface>"), exit(1);
132 setbuf(stdout, NULL);
133 char errbuf[PCAP_ERRBUF_SIZE];
134 printf("Device: %s\n", dev);
137 if (chdir("out")) perror("unable to enter directory 'out'"), exit(1);
139 // We use a zero-timeout. The pcap manual says:
140 // "to_ms is the read time out in milliseconds (a value of 0 means
141 // no time out; on at least some platforms, this means that you may
142 // wait until a sufficient number of packets arrive before seeing
143 // any packets, so you should use a non-zero timeout)."
144 // That's simply not acceptable for us, so we can use a zero timeout
145 // just as well and tell everyone to use a sensible OS. :D
146 pcap_t *handle = pcap_open_live(dev, BUFSIZ, 1, 0, errbuf);
147 if (!handle) printf("can't open device %s: %s\n", dev, errbuf), exit(1);
148 if (pcap_datalink(handle) != DLT_EN10MB)
149 printf("Device %s doesn't provide Ethernet headers - not supported\n", dev), exit(1);
150 if (pcap_setnonblock(handle, 1, errbuf) == -1) printf("unable to go nonblocking\n"), exit(1);
151 int pcap_fd = pcap_get_selectable_fd(handle);
152 if (pcap_fd == -1) printf("unable to get a pcap fd\n"), exit(1);
154 struct bpf_program fp; /* The compiled filter */
155 if (pcap_compile(handle, &fp, "tcp", 1, PCAP_NETMASK_UNKNOWN) == -1) {
156 printf("Couldn't parse filter: %s\n", pcap_geterr(handle));
159 if (pcap_setfilter(handle, &fp) == -1) {
160 printf("Couldn't install filter: %s\n", pcap_geterr(handle));
164 t = round_up(real_seconds(), 2);
165 even = (t&3) == 0; /* are we processing part 2/2 of one encoded bit? */
167 struct timespec dst, delta;
171 // this inner loop runs until we hit a 2s-boundary
175 FD_SET(pcap_fd, &rfds);
177 int r = clock_gettime(CLOCK_REALTIME, &cur);
179 if (timespec_subtract(&delta, &dst, &cur)) break;
180 r = pselect(pcap_fd+1, &rfds, NULL, NULL, &delta, NULL);
181 if (r == -1) perror("select failed"), exit(1);
186 r = pcap_dispatch(handle, -1, packet_handler, NULL);
187 if (r < 0) printf("pcap_dispatch failed\n"), exit(1);
191 if (even) { // cycle complete
193 HASH_ITER(hh, cons, c, tmp) {
197 c = NULL; // just to be sure
202 bit = (c->bytesA < c->bytesB) ? '1' : '0';
203 int fd = open(c->name, O_WRONLY|O_APPEND|O_CREAT, 0666);
205 perror("unable to open confile");
207 w:; ssize_t r = write(fd, &bit, 1);
208 if (r == -1 && errno == EINTR) goto w;
209 if (r == -1) perror("confile write failed");
210 if (r == 0) puts("confile write failed");