Update to the FreeRADIUS version.
[metze/wireshark/wip.git] / trigcap.c
1 /*
2  * trigcap
3  * a simple triggered libpcap-based capture agent
4  *
5  * (c) 2007, Luis E. Garcia Ontanon <luis@ontanon.org>
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20  *
21  */
22
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <stdarg.h>
26 #include <string.h>
27 #include <signal.h>
28 #include <errno.h>
29 #include <getopt.h>
30
31 #include <wsutil/wspcap.h>
32
33 static int dumping;
34 static volatile int keep_going;
35 static pcap_t* listener;
36 static struct bpf_program stop_filter;
37 static int captured = 0;
38 static int debug_level = 0;
39
40 static void panic(int err, const char* fmt, ...) {
41         va_list ap;
42         va_start(ap,fmt);
43         vfprintf(stderr,fmt,ap);
44         va_end(ap);
45         exit(err);
46 }
47
48 static void dprintf(int lev, const char* fmt, ...) {
49         va_list ap;
50
51         if (lev <= debug_level) {
52                 va_start(ap,fmt);
53                 vfprintf(stderr,fmt,ap);
54                 va_end(ap);
55                 fflush(stderr);
56         }
57 }
58
59
60 static void usage(int err) {
61         const char* usage_str = "usage:\n"
62         "trigcap -w outfile -b begin -e end [-f capture] [-i iface] [-s snaplen] [-p] [-q] [-d [-d [-d [-d]]]]\n"
63         "   -w output file\n"
64         "   -b filter to start capturing\n"
65         "   -e filter to stop capturing\n"
66         "   -f capture filter\n"
67         "   -p promiscuous mode\n"
68         "   -s snapshot length\n"
69         "   -q quiet\n"
70         "   -d increase debug level\n"
71         "   -h prints this message\n"
72         ;
73
74         panic(err,usage_str);
75 }
76
77 static void listener_handler(u_char* u, const struct pcap_pkthdr * ph, const u_char* buf) {
78         char errbuf[PCAP_ERRBUF_SIZE];
79
80         dprintf(2,"listener handler invoked dumping=%d\n",dumping);
81
82         if (dumping) {
83                 dprintf(2,"last round\n");
84                 keep_going = 0;
85         } else {
86                 if (pcap_setfilter(listener, &stop_filter) < 0) {
87                         panic(23,"could not apply stop filter to listener: %s\n",pcap_geterr(listener));
88                 }
89
90                 dprintf(2,"apply stop filter to listener\n");
91
92                 if (pcap_setnonblock(listener, 1, errbuf) < 0) {
93                         panic(24,"could not set listener in non blocking mode: %s\n",errbuf);
94                 }
95
96                 dprintf(2,"listener -> non_blocking\n");
97                 dumping = 1;
98         }
99 }
100
101 static void capture_handler(u_char* dumper, const struct pcap_pkthdr * ph, const u_char* buf) {
102         dprintf(4,"capture handler invoked dumping=%d\n",dumping);
103         if (dumping) {
104                 captured++;
105                 pcap_dump(dumper, ph, buf);
106         }
107 }
108
109 static void sig_int(int sig) {
110         keep_going = 0;
111 }
112
113 int main(int argc, char** argv) {
114         char errbuf[PCAP_ERRBUF_SIZE];
115         char* interface = NULL;
116         char* outfile = NULL;
117         guint snaplen = 65536;
118         char* start_filter_str = NULL;
119         char* stop_filter_str = NULL;
120         char* capture_filter_str = NULL;
121         int promisc = 0;
122         int quiet = 0;
123         struct bpf_program start_filter;
124         struct bpf_program capture_filter;
125         pcap_t* capturer = NULL;
126         pcap_dumper_t* dumper = NULL;
127         int opt;
128
129         while ((opt = getopt(argc, argv, "i:w:s:b:e:f:phdq")) != -1) {
130                 switch (opt) {
131                         case 'i':
132                                 if (interface) panic(1,"interface already given");
133                                 interface = g_strdup(optarg);
134                                 break;
135                         case 'w':
136                                 if (outfile) panic(3,"output file already given");
137                                 outfile = g_strdup(optarg);
138                                 break;
139                         case 's':
140                                 snaplen = strtoul(optarg,NULL,10);
141                                 if ( snaplen == 0 )
142                                         panic(4,"invalid snaplen");
143                                 break;
144                         case 'b':
145                                 if (start_filter_str) panic(5,"start filter already given");
146                                 start_filter_str = g_strdup(optarg);
147                                 break;
148                         case 'e':
149                                 if (stop_filter_str) panic(6,"stop filter already given");
150                                 stop_filter_str = g_strdup(optarg);
151                                 break;
152                         case 'f':
153                                 if (capture_filter_str) panic(7,"capture filter already given");
154                                 capture_filter_str = g_strdup(optarg);
155                                 break;
156                         case 'p':
157                                 promisc = 1;
158                                 break;
159                         case 'q':
160                                 quiet = 1;
161                                 break;
162                         case 'd':
163                                 debug_level++;
164                                 break;
165                         case 'h':
166                         default:
167                                 usage(0);
168                                 break;
169                         }
170                 }
171
172         dprintf(1,"starting with:\n interface: %s\n snaplen: %d\n promisc: %d"
173                         "\n outfile: %s\n capture filter: %s\n start: %s\n stop: %s\n debug level: %d\n",
174                         interface ? interface : "to be chosen",
175                         snaplen,
176                         promisc,
177                         outfile ? outfile : "** missing **",
178                         capture_filter_str ? capture_filter_str : "** none given **",
179                         start_filter_str ? start_filter_str : "** missing **",
180                         stop_filter_str ? stop_filter_str : "** missing **",
181                         debug_level);
182
183         if (! ( start_filter_str && stop_filter_str && outfile ) ) {
184                 usage(10);
185         }
186
187         if (! interface) {
188                 interface = pcap_lookupdev(errbuf);
189                 if (!interface) {
190                         panic(11, "could not obtain an interface: %s\n",errbuf);
191                 }
192         }
193
194 #ifdef HAVE_PCAP_OPEN
195         if ( ! ( capturer = pcap_open(interface, snaplen, promisc, 1, NULL, errbuf) )) {
196 #else
197         if ( ! ( capturer = pcap_open_live(interface, snaplen, promisc, 1, errbuf) )) {
198 #endif
199                 panic(12,"could not open interface '%s' for listener: %s\n",interface,errbuf);
200         }
201
202         dprintf(1,"opened listener (%s,%d,%d)\n",interface,snaplen, promisc);
203
204         if (pcap_compile(listener, &start_filter, start_filter_str, 1, 0) < 0) {
205                 panic(13,"could not compile start filter: %s\n",pcap_geterr(listener));
206         }
207
208         dprintf(2,"compiled start filter %s\n",start_filter_str);
209
210         if (pcap_compile(listener, &stop_filter, stop_filter_str, 1, 0) < 0) {
211                 panic(14,"could not compile stop filter: %s\n",pcap_geterr(listener));
212         }
213
214         dprintf(2,"compiled stop filter %s\n",stop_filter_str);
215
216 #ifdef HAVE_PCAP_OPEN
217         if ( ! ( capturer = pcap_open(interface, snaplen, promisc, 1, NULL, errbuf) )) {
218 #else
219         if ( ! ( capturer = pcap_open_live(interface, snaplen, promisc, 1, errbuf) )) {
220 #endif
221                 panic(15,"could not open interface '%s' for capturer: %s\n",interface, errbuf);
222         }
223
224         dprintf(1,"opened capturer (%s,%d,%d)\n",interface,snaplen, promisc);
225
226         if (capture_filter_str) {
227                 if (pcap_compile(capturer, &capture_filter, capture_filter_str, 1, 0) < 0) {
228                         panic(16,"could not compile capture filter: %s\n",pcap_geterr(capturer));
229                 }
230                 if (pcap_setfilter(capturer, &capture_filter) < 0) {
231                         panic(17,"could not apply start filter to capturer: %s\n",pcap_geterr(capturer));
232                 }
233
234                 dprintf(2,"compiled and set capture filter (%s)\n",capture_filter_str);
235         }
236
237         if (pcap_setfilter(listener, &start_filter) < 0) {
238                 panic(18,"could not apply start filter to listener: %s\n",pcap_geterr(listener));
239         }
240         dprintf(2,"set start filter on listener\n");
241
242
243         if (pcap_setnonblock(listener, 0, errbuf) < 0) {
244                 panic(19,"could not set listener in blocking mode: %s\n",errbuf);
245         }
246         dprintf(2,"listener -> blocking\n");
247
248         if (pcap_setnonblock(capturer, 1, errbuf) < 0) {
249                 panic(20,"could not set capturer in non blocking mode: %s\n",errbuf);
250         }
251         dprintf(2,"capturer -> non_blocking\n");
252
253         if (! (dumper = pcap_dump_open(listener,outfile)) ) {
254                 panic(21,"open dumper file '%s': %s\n",outfile,pcap_geterr(listener));
255         }
256         dprintf(2,"opened dumper file '%s'\n",outfile);
257
258         signal(SIGINT, sig_int);
259 #ifdef SIGQUIT
260         signal(SIGQUIT, sig_int);
261 #endif
262 #ifdef SIGTERM
263         signal(SIGTERM, sig_int);
264 #endif
265 #ifdef SIGSTOP
266         signal(SIGSTOP, sig_int);
267 #endif
268
269         keep_going = 1;
270         dumping = 0;
271
272         do {
273                 if (pcap_dispatch(listener, -1, listener_handler, NULL) < 0 ) {
274                         panic(22,"pcap_dispatch(listener) failed: %s\n",pcap_geterr(listener));
275                 }
276
277                 if (pcap_dispatch(capturer, -1, capture_handler, (void*)dumper) < 0 ) {
278                         panic(23,"pcap_dispatch(capturer) failed: %s\n",pcap_geterr(capturer));
279                 }
280         } while(keep_going);
281
282         if (!quiet) {
283                 printf("%d packets captured\n",captured);
284         }
285
286         dprintf(1,"done!\n");
287
288         pcap_dump_close(dumper);
289         pcap_close(listener);
290         pcap_close(capturer);
291
292         return 0;
293 }
294
295 /*
296  * Editor modelines  -  http://www.wireshark.org/tools/modelines.html
297  *
298  * Local variables:
299  * c-basic-offset: 8
300  * tab-width: 8
301  * indent-tabs-mode: t
302  * End:
303  *
304  * vi: set shiftwidth=8 tabstop=8 noexpandtab:
305  * :indentSize=8:tabSize=8:noTabs=false:
306  */