If we're given the "-k" flag, don't start the capture until after we've:
[obnox/wireshark/wip.git] / capture.c
1 /* capture.c
2  * Routines for packet capture windows
3  *
4  * $Id: capture.c,v 1.73 1999/09/30 06:11:43 guy Exp $
5  *
6  * Ethereal - Network traffic analyzer
7  * By Gerald Combs <gerald@zing.org>
8  * Copyright 1998 Gerald Combs
9  *
10  * 
11  * This program is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU General Public License
13  * as published by the Free Software Foundation; either version 2
14  * of the License, or (at your option) any later version.
15  * 
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  * 
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
24  */
25
26
27 #ifdef HAVE_CONFIG_H
28 # include "config.h"
29 #endif
30
31 #ifdef HAVE_LIBPCAP
32
33 #ifdef HAVE_SYS_TYPES_H
34 # include <sys/types.h>
35 #endif
36
37 #ifdef HAVE_SYS_STAT_H
38 # include <sys/stat.h>
39 #endif
40
41 #include <gtk/gtk.h>
42 #include <stdlib.h>
43 #include <stdio.h>
44 #include <ctype.h>
45 #include <string.h>
46
47 #ifdef HAVE_UNISTD_H
48 #include <unistd.h>
49 #endif
50
51 #include <time.h>
52
53 #ifdef HAVE_SYS_SOCKET_H
54 #include <sys/socket.h>
55 #endif
56
57 #ifdef HAVE_SYS_IOCTL_H
58 #include <sys/ioctl.h>
59 #endif
60
61 #ifdef HAVE_NET_IF_H
62 #include <net/if.h>
63 #endif
64
65 #include <signal.h>
66 #include <errno.h>
67
68 #ifdef NEED_SNPRINTF_H
69 # ifdef HAVE_STDARG_H
70 #  include <stdarg.h>
71 # else
72 #  include <varargs.h>
73 # endif
74 # include "snprintf.h"
75 #endif
76
77 #include "gtk/main.h"
78 #include "packet.h"
79 #include "file.h"
80 #include "gtk/menu.h"
81 #include "capture.h"
82 #include "util.h"
83 #include "prefs.h"
84 #include "globals.h"
85
86 static void capture_stop_cb(GtkWidget *, gpointer);
87 static void capture_pcap_cb(u_char *, const struct pcap_pkthdr *,
88   const u_char *);
89 static float pct(gint, gint);
90
91 typedef struct _loop_data {
92   gint           go;
93   gint           max;
94   gint           linktype;
95   gint           sync_packets;
96   packet_counts  counts;
97   wtap_dumper   *pdh;
98 } loop_data;
99
100 void
101 do_capture(void)
102 {
103   char tmpname[128+1];
104   u_char c;
105   int i;
106   guint byte_count;
107   char *msg;
108
109   /* Choose a random name for the capture buffer */
110   cf.save_file_fd = create_tempfile(tmpname, sizeof tmpname, "ether");
111   if (cf.save_file_fd == -1) {
112     simple_dialog(ESD_TYPE_WARN, NULL,
113         "The file to which the capture would be saved (\"%s\")"
114         "could not be opened: %s.", tmpname, strerror(errno));
115     return;
116   }
117   close_cap_file(&cf, info_bar, file_ctx);
118   if (cf.save_file != NULL) {
119     /* If the current file is a temporary capture file, remove it. */
120     if (!cf.user_saved)
121       unlink(cf.save_file); /* silently ignore error */
122     g_free(cf.save_file);
123   }
124   cf.save_file = g_strdup(tmpname);
125   cf.user_saved = 0;
126   
127   if (sync_mode || fork_mode) { /*  use fork() for capture */
128     int  fork_child;
129     char ssnap[24];
130     char scount[24];    /* need a constant for len of numbers */
131     char save_file_fd[24];
132     int err;
133
134     sprintf(ssnap,"%d",cf.snap); /* in lieu of itoa */
135     sprintf(scount,"%d",cf.count);
136     sprintf(save_file_fd,"%d",cf.save_file_fd);
137     signal(SIGCHLD, SIG_IGN);
138     if (sync_mode)
139       pipe(sync_pipe);
140     if ((fork_child = fork()) == 0) {
141       /* args: -k -- capture
142        * -i interface specification
143        * -w file to write
144        * -W file descriptor to write
145        * -c count to capture
146        * -Q quit after capture (forces -k)
147        * -s snaplen
148        * -S sync mode
149        * -m / -b fonts
150        * -f "filter expression"
151        */
152        if (sync_mode) {
153          close(1);
154          dup(sync_pipe[1]);
155          close(sync_pipe[0]);
156          execlp(ethereal_path, CHILD_NAME, "-k", "-Q", "-i", cf.iface,
157                 "-w", cf.save_file, "-W", save_file_fd,
158                 "-c", scount, "-s", ssnap, "-S", 
159                 "-m", medium_font, "-b", bold_font,
160                 (cf.cfilter == NULL)? 0 : "-f",
161                 (cf.cfilter == NULL)? 0 : cf.cfilter,
162                 (const char *)NULL);    
163        }
164        else {
165          execlp(ethereal_path, CHILD_NAME, "-k", "-Q", "-i", cf.iface,
166                 "-w", cf.save_file, "-W", save_file_fd,
167                 "-c", scount, "-s", ssnap,
168                 "-m", medium_font, "-b", bold_font,
169                 (cf.cfilter == NULL)? 0 : "-f",
170                 (cf.cfilter == NULL)? 0 : cf.cfilter,
171                 (const char *)NULL);
172        }
173     }
174     else {
175        cf.filename = cf.save_file;
176        if (sync_mode) {
177          close(sync_pipe[1]);
178
179          /* Read a byte count from "sync_pipe[0]", terminated with a
180             colon; if the count is 0, the child process created the
181             capture file and we should start reading from it, otherwise
182             the capture couldn't start and the count is a count of bytes
183             of error message, and we should display the message. */
184          byte_count = 0;
185          for (;;) {
186            i = read(sync_pipe[0], &c, 1);
187            if (i == 0) {
188              /* EOF - the child process died.
189                 XXX - reap it and report the status. */
190              simple_dialog(ESD_TYPE_WARN, NULL, "Capture child process died");
191              return;
192            }
193            if (c == ';')
194              break;
195            if (!isdigit(c)) {
196              /* Child process handed us crap. */
197              simple_dialog(ESD_TYPE_WARN, NULL,
198                 "Capture child process sent us a bad message");
199              return;
200            }
201            byte_count = byte_count*10 + c - '0';
202          }
203          if (byte_count == 0) {
204            /* Success. */
205            err = tail_cap_file(cf.save_file, &cf);
206            if (err != 0) {
207              simple_dialog(ESD_TYPE_WARN, NULL,
208                         file_open_error_message(err, FALSE), cf.save_file);
209            }
210          } else {
211            /* Failure. */
212            msg = g_malloc(byte_count + 1);
213            if (msg == NULL) {
214              simple_dialog(ESD_TYPE_WARN, NULL,
215                 "Capture child process failed, but its error message was too big.");
216            } else {
217              i = read(sync_pipe[0], msg, byte_count);
218              if (i < 0) {
219                 simple_dialog(ESD_TYPE_WARN, NULL,
220                   "Capture child process failed: Error %s reading its error message.",
221                   strerror(errno));
222              } else if (i == 0) {
223                 simple_dialog(ESD_TYPE_WARN, NULL,
224                   "Capture child process failed: EOF reading its error message.");
225              } else
226                 simple_dialog(ESD_TYPE_WARN, NULL, msg);
227              g_free(msg);
228            }
229          }
230        }
231     }
232   }
233   else
234     capture();
235 }
236
237 void
238 capture(void)
239 {
240   GtkWidget  *cap_w, *main_vb, *count_lb, *tcp_lb, *udp_lb, *icmp_lb,
241              *ospf_lb, *gre_lb, *netbios_lb, *other_lb, *stop_bt;
242   pcap_t     *pch;
243   gchar       err_str[PCAP_ERRBUF_SIZE], label_str[32];
244   loop_data   ld;
245   bpf_u_int32 netnum, netmask;
246   time_t      upd_time, cur_time;
247   int         err, inpkts;
248   char        errmsg[1024+1];
249
250   ld.go             = TRUE;
251   ld.counts.total   = 0;
252   ld.max            = cf.count;
253   ld.linktype       = WTAP_ENCAP_UNKNOWN;
254   ld.sync_packets   = 0;
255   ld.counts.tcp     = 0;
256   ld.counts.udp     = 0;
257   ld.counts.icmp    = 0;
258   ld.counts.ospf    = 0;
259   ld.counts.gre     = 0;
260   ld.counts.netbios = 0;
261   ld.counts.other   = 0;
262   ld.pdh            = NULL;
263
264   /* Open the network interface to capture from it. */
265   pch = pcap_open_live(cf.iface, cf.snap, 1, 250, err_str);
266
267   if (pch == NULL) {
268     /* Well, we couldn't start the capture. */
269     if (!sync_mode && !fork_mode) {
270       /* In fork mode, we shouldn't do any UI stuff until we pop up the
271          capture-progress window, and, since we couldn't start the
272          capture, we haven't popped it up. */
273       while (gtk_events_pending()) gtk_main_iteration();
274     }
275     snprintf(errmsg, sizeof errmsg,
276       "The capture session could not be initiated (%s).\n"
277       "Please check to make sure you have sufficient permissions, and that\n"
278       "you have the proper interface specified.", err_str);
279     goto error;
280   }
281
282   if (cf.cfilter) {
283     /* A capture filter was specified; set it up. */
284     if (pcap_lookupnet (cf.iface, &netnum, &netmask, err_str) < 0) {
285       snprintf(errmsg, sizeof errmsg,
286         "Can't use filter:  Couldn't obtain netmask info (%s).", err_str);
287       goto error;
288     }
289     if (pcap_compile(pch, &cf.fcode, cf.cfilter, 1, netmask) < 0) {
290       snprintf(errmsg, sizeof errmsg, "Unable to parse filter string (%s).",
291         pcap_geterr(pch));
292       goto error;
293     }
294     if (pcap_setfilter(pch, &cf.fcode) < 0) {
295       snprintf(errmsg, sizeof errmsg, "Can't install filter (%s).",
296         pcap_geterr(pch));
297       goto error;
298     }
299   }
300
301   /* Set up to write to the capture file. */
302   ld.linktype = wtap_pcap_encap_to_wtap_encap(pcap_datalink(pch));
303   if (ld.linktype == WTAP_ENCAP_UNKNOWN) {
304     strcpy(errmsg, "The network you're capturing from is of a type"
305              " that Ethereal doesn't support.");
306     goto error;
307   }
308   ld.pdh = wtap_dump_fdopen(cf.save_file_fd, WTAP_FILE_PCAP,
309                 ld.linktype, pcap_snapshot(pch), &err);
310
311   if (ld.pdh == NULL) {
312     /* We couldn't set up to write to the capture file. */
313     switch (err) {
314
315     case WTAP_ERR_CANT_OPEN:
316       strcpy(errmsg, "The file to which the capture would be saved"
317                " couldn't be created for some unknown reason.");
318       break;
319
320     case WTAP_ERR_SHORT_WRITE:
321       strcpy(errmsg, "A full header couldn't be written to the file"
322                " to which the capture would be saved.");
323       break;
324
325     default:
326       if (err < 0) {
327         sprintf(errmsg, "The file to which the capture would be"
328                      " saved (\"%s\") could not be opened: Error %d.",
329                         cf.save_file, err);
330       } else {
331         sprintf(errmsg, "The file to which the capture would be"
332                      " saved (\"%s\") could not be opened: %s.",
333                         cf.save_file, strerror(err));
334       }
335       break;
336     }
337     goto error;
338   }
339
340   if (sync_mode) {
341     /* Well, we should be able to start capturing.
342
343        Sync out the capture file, so the header makes it to the file
344        system, and send a "capture started successfully and capture
345        file created" message to our parent so that they'll open the
346        capture file and update its windows to indicate that we have
347        a live capture in progress. */
348     fflush(wtap_dump_file(ld.pdh));
349     write(1, "0;", 2);
350   }
351
352   cap_w = gtk_window_new(GTK_WINDOW_TOPLEVEL);
353   gtk_window_set_title(GTK_WINDOW(cap_w), "Ethereal: Capture / Playback");
354
355   /* Container for capture display widgets */
356   main_vb = gtk_vbox_new(FALSE, 1);
357   gtk_container_border_width(GTK_CONTAINER(main_vb), 5);
358   gtk_container_add(GTK_CONTAINER(cap_w), main_vb);
359   gtk_widget_show(main_vb);
360
361   count_lb = gtk_label_new("Count: 0");
362   gtk_box_pack_start(GTK_BOX(main_vb), count_lb, FALSE, FALSE, 3);
363   gtk_widget_show(count_lb);
364
365   tcp_lb = gtk_label_new("TCP: 0 (0.0%)");
366   gtk_box_pack_start(GTK_BOX(main_vb), tcp_lb, FALSE, FALSE, 3);
367   gtk_widget_show(tcp_lb);
368
369   udp_lb = gtk_label_new("UDP: 0 (0.0%)");
370   gtk_box_pack_start(GTK_BOX(main_vb), udp_lb, FALSE, FALSE, 3);
371   gtk_widget_show(udp_lb);
372
373   icmp_lb = gtk_label_new("ICMP: 0 (0.0%)");
374   gtk_box_pack_start(GTK_BOX(main_vb), icmp_lb, FALSE, FALSE, 3);
375   gtk_widget_show(icmp_lb);
376
377   ospf_lb = gtk_label_new("OSPF: 0 (0.0%)");
378   gtk_box_pack_start(GTK_BOX(main_vb), ospf_lb, FALSE, FALSE, 3);
379   gtk_widget_show(ospf_lb);
380
381   gre_lb = gtk_label_new("GRE: 0 (0.0%)");
382   gtk_box_pack_start(GTK_BOX(main_vb), gre_lb, FALSE, FALSE, 3);
383   gtk_widget_show(gre_lb);
384
385   netbios_lb = gtk_label_new("NetBIOS: 0 (0.0%)");
386   gtk_box_pack_start(GTK_BOX(main_vb), netbios_lb, FALSE, FALSE, 3);
387   gtk_widget_show(netbios_lb);
388
389   other_lb = gtk_label_new("Other: 0 (0.0%)");
390   gtk_box_pack_start(GTK_BOX(main_vb), other_lb, FALSE, FALSE, 3);
391   gtk_widget_show(other_lb);
392
393   stop_bt = gtk_button_new_with_label ("Stop");
394   gtk_signal_connect(GTK_OBJECT(stop_bt), "clicked",
395     GTK_SIGNAL_FUNC(capture_stop_cb), (gpointer) &ld);
396   gtk_box_pack_end(GTK_BOX(main_vb), stop_bt, FALSE, FALSE, 3);
397   GTK_WIDGET_SET_FLAGS(stop_bt, GTK_CAN_DEFAULT);
398   gtk_widget_grab_default(stop_bt);
399   GTK_WIDGET_SET_FLAGS(stop_bt, GTK_CAN_DEFAULT);
400   gtk_widget_grab_default(stop_bt);
401   gtk_widget_show(stop_bt);
402
403   gtk_widget_show(cap_w);
404   gtk_grab_add(cap_w);
405
406   upd_time = time(NULL);
407   while (ld.go) {
408     while (gtk_events_pending()) gtk_main_iteration();
409     inpkts = pcap_dispatch(pch, 1, capture_pcap_cb, (u_char *) &ld);
410     if (inpkts > 0)
411       ld.sync_packets += inpkts;
412     /* Only update once a second so as not to overload slow displays */
413     cur_time = time(NULL);
414     if (cur_time > upd_time) {
415       upd_time = cur_time;
416
417       sprintf(label_str, "Count: %d", ld.counts.total);
418       gtk_label_set(GTK_LABEL(count_lb), label_str);
419
420       sprintf(label_str, "TCP: %d (%.1f%%)", ld.counts.tcp,
421                 pct(ld.counts.tcp, ld.counts.total));
422       gtk_label_set(GTK_LABEL(tcp_lb), label_str);
423
424       sprintf(label_str, "UDP: %d (%.1f%%)", ld.counts.udp,
425                 pct(ld.counts.udp, ld.counts.total));
426       gtk_label_set(GTK_LABEL(udp_lb), label_str);
427
428       sprintf(label_str, "ICMP: %d (%.1f%%)", ld.counts.icmp,
429                 pct(ld.counts.icmp, ld.counts.total));
430       gtk_label_set(GTK_LABEL(icmp_lb), label_str);
431
432       sprintf(label_str, "OSPF: %d (%.1f%%)", ld.counts.ospf,
433                 pct(ld.counts.ospf, ld.counts.total));
434       gtk_label_set(GTK_LABEL(ospf_lb), label_str);
435
436       sprintf(label_str, "GRE: %d (%.1f%%)", ld.counts.gre,
437                 pct(ld.counts.gre, ld.counts.total));
438       gtk_label_set(GTK_LABEL(gre_lb), label_str);
439
440       sprintf(label_str, "NetBIOS: %d (%.1f%%)", ld.counts.netbios,
441                 pct(ld.counts.netbios, ld.counts.total));
442       gtk_label_set(GTK_LABEL(netbios_lb), label_str);
443
444       sprintf(label_str, "Other: %d (%.1f%%)", ld.counts.other,
445                 pct(ld.counts.other, ld.counts.total));
446       gtk_label_set(GTK_LABEL(other_lb), label_str);
447
448       /* do sync here, too */
449       fflush(wtap_dump_file(ld.pdh));
450       if (sync_mode && ld.sync_packets) {
451         char tmp[20];
452         sprintf(tmp, "%d*", ld.sync_packets);
453         write(1, tmp, strlen(tmp));
454         ld.sync_packets = 0;
455       }
456     }
457   }
458     
459   if (!wtap_dump_close(ld.pdh, &err)) {
460     /* XXX - in fork mode, this may not pop up, or, if it does,
461        it may disappear as soon as we exit.
462
463        We should have the parent process, while it's reading
464        the packet count update messages, catch error messages
465        and pop up a message box if it sees one. */
466     switch (err) {
467
468     case WTAP_ERR_CANT_CLOSE:
469       simple_dialog(ESD_TYPE_WARN, NULL,
470                 "The file to which the capture was being saved"
471                 " couldn't be closed for some unknown reason.");
472       break;
473
474     case WTAP_ERR_SHORT_WRITE:
475       simple_dialog(ESD_TYPE_WARN, NULL,
476                 "Not all the data could be written to the file"
477                 " to which the capture was being saved.");
478       break;
479
480     default:
481       if (err < 0) {
482         simple_dialog(ESD_TYPE_WARN, NULL,
483                 "The file to which the capture was being"
484                 " saved (\"%s\") could not be closed: Error %d.",
485                 cf.save_file, err);
486       } else {
487         simple_dialog(ESD_TYPE_WARN, NULL,
488                 "The file to which the capture was being"
489                 " saved (\"%s\") could not be closed: %s.",
490                 cf.save_file, strerror(err));
491       }
492       break;
493     }
494   }
495   pcap_close(pch);
496
497   gtk_grab_remove(GTK_WIDGET(cap_w));
498   gtk_widget_destroy(GTK_WIDGET(cap_w));
499
500   if (quit_after_cap) {
501     /* DON'T unlink the save file.  Presumably someone wants it. */
502     gtk_exit(0);
503   }
504
505   if ((err = open_cap_file(cf.save_file, &cf)) == 0) {
506     /* Set the read filter to NULL. */
507     cf.rfcode = NULL;
508     err = read_cap_file(&cf);
509     set_menu_sensitivity("/File/Save", TRUE);
510     set_menu_sensitivity("/File/Save As...", FALSE);
511   }
512   return;
513
514 error:
515   /* We couldn't even start the capture, so get rid of the capture
516      file. */
517   unlink(cf.save_file); /* silently ignore error */
518   if (sync_mode) {
519     /* Send the error message to our parent, so they can display a
520        dialog box containing it. */
521     int msglen = strlen(errmsg);
522     char lenbuf[10+1+1];
523     sprintf(lenbuf, "%u;", msglen);
524     write(1, lenbuf, strlen(lenbuf));
525     write(1, errmsg, msglen);
526   } else {
527     /* Display the dialog box ourselves; there's no parent. */
528     simple_dialog(ESD_TYPE_WARN, NULL, errmsg);
529   }
530   if (pch != NULL)
531     pcap_close(pch);
532
533   if (quit_after_cap)
534     gtk_exit(0);
535 }
536
537 static float
538 pct(gint num, gint denom) {
539   if (denom) {
540     return (float) num * 100.0 / (float) denom;
541   } else {
542     return 0.0;
543   }
544 }
545
546 static void
547 capture_stop_cb(GtkWidget *w, gpointer data) {
548   loop_data *ld = (loop_data *) data;
549   
550   ld->go = FALSE;
551 }
552
553 static void
554 capture_pcap_cb(u_char *user, const struct pcap_pkthdr *phdr,
555   const u_char *pd) {
556   struct wtap_pkthdr whdr;
557   loop_data *ld = (loop_data *) user;
558   int err;
559
560   if ((++ld->counts.total >= ld->max) && (ld->max > 0)) 
561   {
562      ld->go = FALSE;
563   }
564   if (ld->pdh) {
565      whdr.ts = phdr->ts;
566      whdr.caplen = phdr->caplen;
567      whdr.len = phdr->len;
568      whdr.pkt_encap = ld->linktype;
569
570      /* XXX - do something if this fails */
571      wtap_dump(ld->pdh, &whdr, pd, &err);
572   }
573     
574   switch (ld->linktype) {
575     case WTAP_ENCAP_ETHERNET:
576       capture_eth(pd, phdr->caplen, &ld->counts);
577       break;
578     case WTAP_ENCAP_FDDI:
579     case WTAP_ENCAP_FDDI_BITSWAPPED:
580       capture_fddi(pd, phdr->caplen, &ld->counts);
581       break;
582     case WTAP_ENCAP_TR:
583       capture_tr(pd, phdr->caplen, &ld->counts);
584       break;
585     case WTAP_ENCAP_NULL:
586       capture_null(pd, phdr->caplen, &ld->counts);
587       break;
588     case WTAP_ENCAP_PPP:
589       capture_ppp(pd, phdr->caplen, &ld->counts);
590       break;
591     case WTAP_ENCAP_RAW_IP:
592       capture_raw(pd, phdr->caplen, &ld->counts);
593       break;
594     /* XXX - FreeBSD may append 4-byte ATM pseudo-header to DLT_ATM_RFC1483,
595        with LLC header following; we should implement it at some
596        point. */
597   }
598 }
599
600 #endif /* HAVE_LIBPCAP */