3 * Copyright August 2007 TJ <linux@tjworld.net>
5 * Checks that network packets seen by libpcap are seen at the netfilters
6 * level and haven't been silently discarded by the kernel.
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 3 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program in the file LICENSE-GPLv3.txt;
20 * if not, you can view it online at http://www.gnu.org/copyleft/gpl.html
30 #include <sys/socket.h>
31 #include <netinet/in.h>
32 #include <netinet/ether.h>
33 #include <netinet/ip.h>
34 #include <netinet/tcp.h>
35 #include <arpa/inet.h>
36 #include <netinet/if_ether.h>
39 #include "packeteer.h"
41 extern int size_ethernet; // sizes calculated once
44 extern int verbose; // flag controlling debugging messages
45 extern unsigned int headers_done;
46 extern struct in_addr_filter *ip_addr_filters; // linked-list of source IP addresses to match
47 extern unsigned char tcp_flags_filter; // TCP flags to match (bitwise-OR)
49 unsigned long pcap_count = 0; // packet counter
51 int pcap_control = 0; // thread-running control signal
52 pthread_t pcap_thread_id;
53 pthread_mutex_t pcap_mutex = PTHREAD_MUTEX_INITIALIZER;
55 pcap_t *descr=NULL; // descriptor for pcap
57 /* replacement for strcpy() that allocates the required memory internally */
58 char *my_strcpy(const char *src) {
59 int count = 0, length = 0;
62 // find the length of the zero-terminated string
63 for (length=0; src[length] != 0; length++);
65 dest = (char *)malloc(length+1);
67 for (count=0; count <= length; count++) {
68 dest[count] = src[count];
72 fprintf(stderr, "my_strcpy(): malloc() failed\n");
77 /* Called from pcap with pointer to a new packet */
78 void pcap_callback(u_char *useless, const struct pcap_pkthdr *pkthdr, const u_char *packet) {
79 int ip_addr_match = 0;
80 unsigned char tcp_flags_match = 0;
81 struct in_addr_filter *ip_walk = ip_addr_filters;
84 struct pcap_pkthdr hdr; /* pcap.h */
87 const struct ether_header *ethernet; /* The ethernet header */
88 const struct iphdr *ip; /* The IP header */
89 const struct tcphdr *tcp; /* The TCP header */
90 const char *payload; /* Packet payload */
92 ethernet = (struct ether_header*)(packet);
93 ip = (struct iphdr*)(packet + size_ethernet);
94 tcp = (struct tcphdr*)(packet + size_ethernet + size_ip);
95 payload = (u_char *)(packet + size_ethernet + size_ip + size_tcp);
99 if (ip_addr_filters == NULL)
100 ip_addr_match++; // no filter set, so report everything
102 while(ip_walk != NULL) {
103 if (ip_walk->ip_addr.s_addr == s.s_addr) {
104 ip_addr_match++; // got a match
105 if (verbose) fprintf(stderr, "pcap: matched IP %s\n", inet_ntoa(ip_walk->ip_addr));
107 ip_walk = ip_walk->next;
111 if (ip_addr_match) { // IP address matches filter
113 // because tcphdr defines flags individually, to get the flags byte we have to index into the header
114 tcp_flags_match = *( ((unsigned char *)tcp) + 13) & tcp_flags_filter;
115 if (verbose) fprintf(stderr, "pcap: result TCP flags 0x%2.2X, filter 0x%2.2X, TCP packet flags 0x%2.2X\n", tcp_flags_match, tcp_flags_filter, *( ((unsigned char *)tcp) + 13) );
117 if (tcp_flags_match) { // TCP flags match filter
122 fprintf(stderr, "pcap: %10s %10u %15s %4.4X %4.4X %1d %1d %10u %10u %6d\n",
123 print_time(NULL), ++pcap_count, inet_ntoa(s), ntohs(ip->check), ntohs(tcp->check),
124 tcp->syn, tcp->ack, tcp->seq, tcp->ack_seq, pkthdr->len);
127 packet_pcap(pcap_count, ethernet, ip, tcp, pkthdr->len); // register the packet with the tracker
132 /* main loop runs in its own thread. Waits on data available for read on a pcap file descriptor.
133 When new data is available causes pcap to invoke the callback function.
135 void *pcap_thread(void *data) {
140 if (verbose) fprintf(stderr, "pcap_thread(): running\n");
141 fd = pcap_fileno(descr);
142 if (verbose) fprintf(stderr, "pcap: fd=%d\n", fd);
146 FD_SET(fd, &fd_wait);
149 st.tv_usec = 0; /* 1000 = 1 second */
151 // wait up to 1 second for input
152 t=select(fd+1, &fd_wait, NULL, NULL, &st);
156 if (errno == EINTR || errno == EAGAIN) continue;
157 fprintf(stderr, "pcap: Error in main loop\n");
158 pcap_control = 0; // force loop to end
161 case 0: // timed out, no trafffic
162 // fprintf(stderr, "p"); // for debugging: prove the timer is running
165 default: // packets available
166 pcap_dispatch(descr, 1, (void *) pcap_callback, NULL);
168 if (pcap_control == 0) // parent thread's signal to quit
177 * Prepares libpcap for capturing
179 * @device select the device name: "eth1"
180 * @pcap_filter set a filter rule of the form: "dst host 10.2.3.4 and tcp port 80"
181 * @return 1 if successful; 0 if failed
183 int pcap_init(char *device, char *pcap_filter) {
185 const u_char *packet;
188 pcap_if_t *this_dev, *alldevsp;
189 int ret=1; // default return value, failed
192 char errbuf[PCAP_ERRBUF_SIZE];
193 struct bpf_program fp;
195 if (verbose) fprintf(stderr, "calling pcap_findalldevs()\n");
196 if (pcap_findalldevs(&alldevsp, errbuf) == 0) {
197 if (verbose) fprintf(stderr, "pcap_findalldevs() done.\n");
199 while (this_dev != NULL) {
200 if (verbose) fprintf(stderr, "device %s\n",this_dev->name);
201 if (strcmp(device, this_dev->name) == 0) {
202 dev = this_dev->name;
205 this_dev = this_dev->next;
209 fprintf(stderr, "Error: pcap_findalldevs()\n");
211 if (dev) { // system has a device matching the one we want
212 if (verbose) fprintf(stderr, "pcap: initialising %s with rule \"%s\"\n", dev, pcap_filter);
213 pcap_lookupnet(dev, &netp, &maskp, errbuf);
214 if (verbose) fprintf(stderr, "pcap_lookupnet() done\n");
215 /* open device for reading */
216 descr = pcap_open_live(dev, BUFSIZ, 0, 1024, errbuf);
217 if (verbose) fprintf(stderr, "pcap_open_live() done\n");
219 pcap_freealldevs(alldevsp); // free list memory
221 if (verbose) fprintf(stderr, "pcap_freealldevs() done\n");
224 // compile the 'filter' program
225 if (verbose) fprintf(stderr, "my_strcpy(\"%s\")\n", pcap_filter);
226 filter = my_strcpy(pcap_filter);
227 if (verbose) fprintf(stderr, "filter@%lx=%lx=\"%s\")\n",&filter, filter, filter);
228 if (verbose) fprintf(stderr, "pcap_compile(%lx, %lx, \"%s\", %d, %d)\n", descr, &fp, filter, 1, htonl(0xFFFF0000));
229 if(pcap_compile(descr, &fp, filter, 0, 0) != -1) { // compile the rule
230 if (verbose) fprintf(stderr, "pcap_compile() done\n");
231 // set the compiled program as the filter
232 if(pcap_setfilter(descr, &fp) != -1) {
233 pcap_freecode(&fp); // release memory
234 free(filter); // release memory allocated by my_strcpy()
238 if (verbose) fprintf(stderr, "pcap_setnonblock()\n");
239 if(pcap_setnonblock(descr, 1, errbuf) != -1) {
243 fprintf(stderr, "Error pcap_setnonblock(): %s\n", dev, errbuf);
248 fprintf(stderr, "Error pcap_setfilter()\n");
253 fprintf(stderr, "Error pcap_compile(): %s\n", pcap_geterr(descr));
258 fprintf(stderr, "Error pcap_open_live(): %s\n",errbuf);
263 fprintf(stderr, "Error device %d not found\n", device);
266 // clean-up if errors occurred
267 if (ret > 2) pcap_close(descr);
269 if (verbose) fprintf (stderr, "leaving pcap_init()\n");
273 /* Create and start main-loop thread */
274 int pcap_start(void) {
275 if (verbose) fprintf(stderr, "pcap_start(): starting\n");
276 pcap_control = 1; // run thread
277 if (verbose) fprintf(stderr, "pcap_start(): creating thread\n");
278 pthread_create(&pcap_thread_id, NULL, pcap_thread, NULL);
279 if (verbose) fprintf(stderr, "pcap_start(): done\n");
283 /* Stop main-loop thread and clean up */
284 void pcap_exit(void) {
285 if (verbose) fprintf(stderr, "pcap_exit(): exiting\n");
286 if (pcap_control != 0) {
287 if (verbose) fprintf(stderr, "pcap: stopping thread\n");
288 pthread_mutex_lock(&pcap_mutex);
289 pcap_control = 0; // signal thread to stop
290 pthread_mutex_unlock(&pcap_mutex);
292 // blocks until thread ends
293 pthread_join(pcap_thread_id, NULL);
296 if (verbose) fprintf(stderr, "pcap_exit(): done\n");